Tabs

Flex Responsive Accordion

09 Nov 2022

Адаптований акордеон який калькулює ширину за допомогою JavaScript
HTML
SCSS
PostCSS
JS
                            <section class="our-values">
  <ul class="values-list">
    <li class="values-list__item">
      <img
        src="images/value-img-1.jpg"
        alt=""
        class="values-list__item-img"
      />
      <h3 class="values-list__item-title">WE FIND SOLUTIONS</h3>
      <div class="values-list__item-text" data-simplebar>
        <p>
          Being experts in our field, we work tirelessly to find perfect
          recruitment solutions
        </p>
        <p>We always find a way to deliver</p>
      </div>
    </li>
    <li class="values-list__item">
      <img
        src="images/value-img-2.jpg"
        alt=""
        class="values-list__item-img"
      />
      <h3 class="values-list__item-title">WE EMPOWER INDIVIDUALS</h3>
      <div class="values-list__item-text" data-simplebar>
        <p>We encourage you to reach your full potential</p>
        <p>
          We share ideas and inspire each other to be themselves enabling growth
        </p>
      </div>
    </li>
    <li class="values-list__item">
      <img
        src="images/value-img-1.jpg"
        alt=""
        class="values-list__item-img"
      />
      <h3 class="values-list__item-title">WE WORK COLLABORATIVELY</h3>
      <div class="values-list__item-text" data-simplebar>
        <p>We encourage you to reach your full potential</p>
        <p>
          We share ideas and inspire each other to be themselves enabling growth
        </p>
      </div>
    </li>
    <li class="values-list__item">
      <img
        src="images/value-img-2.jpg"
        alt=""
        class="values-list__item-img"
      />
      <h3 class="values-list__item-title">
        WE SHARE EXPERIENCES & PASS ON KNOWLEDGE
      </h3>
      <div class="values-list__item-text" data-simplebar>
        <p>We encourage you to reach your full potential</p>
        <p>
          We share ideas and inspire each other to be themselves enabling growth
        </p>
      </div>
    </li>
    <li class="values-list__item">
      <img
        src="images/value-img-1.jpg"
        alt=""
        class="values-list__item-img"
      />
      <h3 class="values-list__item-title">WE EXCEED EXPECTATIONS</h3>
      <div class="values-list__item-text" data-simplebar>
        <p>We encourage you to reach your full potential</p>
        <p>
          We share ideas and inspire each other to be themselves enabling growth
        </p>
      </div>
    </li>
    <li class="values-list__item">
      <img
        src="images/value-img-2.jpg"
        alt=""
        class="values-list__item-img"
      />
      <h3 class="values-list__item-title">WE GENUINELY CARE</h3>
      <div class="values-list__item-text" data-simplebar>
        <p>We encourage you to reach your full potential</p>
        <p>
          We share ideas and inspire each other to be themselves enabling growth
        </p>
      </div>
    </li>
  </ul>
</section>
                        
                            .our-values__section-title {
  margin-bottom: 32px;
}

.values-list {
  display: flex;
  flex-wrap: wrap;

  max-width: 1366px;

  margin: 0 auto;

  @include media(501) {
    flex-direction: column;
    flex-wrap: nowrap;
  }
}

.values-list__item {
  --card-width: 227px;

  position: relative;

  display: flex;
  flex-direction: column;
  flex-grow: 1;
  flex-shrink: 1;
  flex-basis: var(--card-width);

  height: 350px;

  padding: 30px 15px;

  color: var(--white);

  cursor: pointer;

  transition: flex ease 250ms, max-height ease 250ms;

  @include media(501) {
    max-height: 77px;
    padding: 0;
    transition: flex ease 600ms, max-height ease 600ms;
  }

  &::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: -1;

    background-color: rgba(0, 0, 0, 0.5);

    transition: background-color ease 250ms;

    @include media(501) {
      transition: background-color ease 600ms;
    }
  }

  &::after {
    content: "\e900";
    position: absolute;
    top: 33px;
    right: 15px;

    font-family: "icomoon" !important;
    speak: never;
    font-style: normal;
    font-weight: normal;
    font-variant: normal;
    text-transform: none;
    line-height: 1;
    -webkit-font-smoothing: antialiased;

    transition: transform ease 250ms;

    @include media(501) {
      transition: transform ease 600ms;
    }
  }

  &.active {
    @include media(501) {
      max-height: 1000px;
    }

    &::before {
      background-color: var(--black);
    }

    &::after {
      transform: rotate(90deg);
    }

    .values-list__item-text {
      overflow: auto;

      max-height: 100%;

      opacity: 1;
      visibility: visible;

      transition: opacity 250ms ease 250ms, visibility 250ms ease 250ms;

      @include media(501) {
        transition: opacity 600ms ease, visibility 600ms ease;
      }

      .simplebar-offset {
        padding-right: 14px;
      }

      .simplebar-scrollbar {
        &::before {
          background-color: var(--white);
        }
      }
    }
  }
}

.values-list__item-img {
  position: absolute;
  top: 0;
  left: 0;
  z-index: -2;

  width: 100%;
  height: 100%;
  object-fit: cover;
}

.values-list__item-title {
  max-width: 150px;
  text-transform: uppercase;

  margin-bottom: 15px;

  font-size: 16px;
  font-weight: 600;
  line-height: 1.5;

  @include media(501) {
    display: flex;
    align-items: center;

    max-width: 100%;
    height: 77px;

    padding: 0 15px;
    margin-bottom: 0;
  }
}

.values-list__item-text {
  width: 100%;

  font-size: 16px;
  font-weight: 300;

  visibility: hidden;
  opacity: 0;

  transition: opacity 0ms ease, visibility 0ms ease;

  &::-webkit-scrollbar {
    width: 2px;
  }

  &::-webkit-scrollbar-thumb {
    background: #fff;
  }

  &::-webkit-scrollbar-track {
    background: #736b6b;
  }

  @include media(501) {
    padding: 0 15px;
  }

  p {
    &:not(:last-child) {
      margin-bottom: 15px;
    }
  }
}
                        
                            .our-values__section-title {
  margin-bottom: 32px;
}

.values-list {
  display: flex;
  flex-wrap: wrap;

  max-width: 1366px;

  margin: 0 auto;

  @mixin media 501 {
    flex-direction: column;
    flex-wrap: nowrap;
  }
}

.values-list__item {
  --card-width: 227px;

  position: relative;

  display: flex;
  flex-direction: column;
  flex-grow: 1;
  flex-shrink: 1;
  flex-basis: var(--card-width);

  height: 350px;

  padding: 30px 15px;

  color: var(--white);

  cursor: pointer;

  transition: flex ease 250ms, max-height ease 250ms;

  @mixin media 501 {
    max-height: 77px;
    padding: 0;
    transition: flex ease 600ms, max-height ease 600ms;
  }

  &::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: -1;

    background-color: rgba(0,0,0,0.5);

    transition: background-color ease 250ms;

    @mixin media 501 {
      transition: background-color ease 600ms;
    }
  }

  &::after {
    content: "\e900";
    position: absolute;
    top: 33px;
    right: 15px;

    font-family: "icomoon" !important;
    speak: never;
    font-style: normal;
    font-weight: normal;
    font-variant: normal;
    text-transform: none;
    line-height: 1;
    -webkit-font-smoothing: antialiased;

    transition: transform ease 250ms;

    @mixin media 501 {
      transition: transform ease 600ms;
    }
  }

  &.active {
    @mixin media 501 {
      max-height: 1000px;
    }

    &::before {
      background-color: var(--black);
    }

    &::after {
      transform: rotate(90deg);
    }

    .values-list__item-text {
      overflow: auto;

      max-height: 100%;

      /* padding-bottom: 24px; */

      opacity: 1;
      visibility: visible;

      transition: opacity 250ms ease 250ms, visibility 250ms ease 250ms;

      @mixin media 501 {
        transition: opacity 600ms ease, visibility 600ms ease;
      }

      .simplebar-offset {
        padding-right: 14px;
      }

      .simplebar-scrollbar {
        &::before {
          background-color: var(--white);
        }
      }
    }
  }
}

.values-list__item-img {
  position: absolute;
  top: 0;
  left: 0;
  z-index: -2;

  width: 100%;
  height: 100%;
  object-fit: cover;
}

.values-list__item-title {
  max-width: 150px;
  text-transform: uppercase;

  margin-bottom: 15px;

  font-size: 16px;
  font-weight: 600;
  line-height: 1.5;

  @mixin media 501 {
    display: flex;
    align-items: center;

    max-width: 100%;
    height: 77px;

    padding: 0 15px;
    margin-bottom: 0;
  }
}

.values-list__item-text {
  width: 100%;

  font-size: 16px;
  font-weight: 300;

  visibility: hidden;
  opacity: 0;

  transition: opacity 0ms ease, visibility 0ms ease;

  &::-webkit-scrollbar {
    width: 2px;
  }

  &::-webkit-scrollbar-thumb {
    background: #fff;
  }

  &::-webkit-scrollbar-track {
    background: #736b6b;
  }

  @mixin media 501 {
    padding: 0 15px;
  }

  p {
    &:not(:last-child) {
      margin-bottom: 15px;
    }
  }
}
                        
                            const ourValues = document.querySelector(".our-values");
if (ourValues) {
  const isMob = window.matchMedia("(max-width: 500px)").matches;
  const valueItems = ourValues.querySelectorAll(".values-list__item");
  let gridCard = takeGridSet(valueItems);
  let activeIndex = null;
  let trueArr = [];
  let { offsetWidth: valueListBlockWidth } =
    ourValues.querySelector(".values-list");
  let trueIndex = 0;

  if (isMob) {
    valueItems.forEach((item, idx) => {
      item.addEventListener("click", () => {
        // Якщо карточка на яку ми натискаємо вже активна, робимо її неактивною
        //  і виходимо з функції
        if (idx === activeIndex) {
          item.classList.remove("active");
          activeIndex = null;
          return;
        }

        // Якщо активна карточка вже є, робимо її неактивною, а ту на яку
        // натиснули робимо активною
        if (activeIndex !== null) {
          valueItems[activeIndex].classList.remove("active");
        }

        activeIndex = idx;

        item.classList.add("active");
      });
    });
  } else {
    valueItems.forEach((item, idx) => {
      item.addEventListener("click", () => {
        // Якщо карточка на яку ми натискаємо вже активна, робимо її
        // неактивною і перераховуємо ширину карток в рядку і виходимо з функції
        if (idx === activeIndex) {
          item.classList.remove("active");

          for (let i = 0; i < trueArr.length; i++) {
            trueArr[i].style.flexBasis = `${Math.floor(
              valueListBlockWidth / trueArr.length - 2
            )}px`;
            activeIndex = null;
          }
          return;
        }

        // якщо вже є активна картка робимо її не активною, а ту на яку
        // натиснули робюимо активною і перераховуємо ширини карток в рядку
        if (activeIndex !== null) {
          valueItems[activeIndex].classList.remove("active");

          for (let i = 0; i < trueArr.length; i++) {
            trueArr[i].style.flexBasis = `${Math.floor(
              valueListBlockWidth / trueArr.length - 2
            )}px`;
          }
        }

        activeIndex = idx;

        item.classList.add("active");

        let accum = 0;

        for (let i = 0; i < gridCard.length; i++) {
          accum += gridCard[i].length;

          if (idx < accum) {
            trueIndex =
              (idx - (accum - gridCard[i].length)) % gridCard[i].length;
            trueArr = gridCard[i];
            break;
          }
        }

        let cardWidth = valueListBlockWidth / trueArr.length;

        for (let i = 0; i < trueArr.length; i++) {
          if (i === trueIndex) {
            trueArr[i].style.flexBasis = `${Math.floor(cardWidth * 1.3)}px`;
          } else {
            trueArr[i].style.flexBasis = `${Math.floor(
              cardWidth - (cardWidth * 0.3) / (trueArr.length - 1) - 2
            )}px`;
          }
        }
      });
    });
  }

  window.addEventListener("resize", () => {
    const activeItem = ourValues.querySelector(".values-list__item.active");

    activeItem?.classList.remove("active");

    activeIndex = null;

    // записуємо нову ширину блоку для корректного калькулювання ширини карточки
    valueListBlockWidth = ourValues.querySelector(".values-list").offsetWidth;

    gridCard = takeGridSet(valueItems);

    valueItems.forEach((item) => (item.style.flexBasis = ""));
  });

  function takeGridSet(valueItems) {
    let gridCard = [];
    let buffer = [];

    for (let i = 0; i < valueItems.length; i++) {
      if (
        i > 0 &&
        valueItems[i].getBoundingClientRect().top !==
        valueItems[i - 1].getBoundingClientRect().top
      ) {
        gridCard.push(buffer);
        buffer = [];
      }

      if (i === valueItems.length - 1) {
        gridCard.push(buffer);
      }

      buffer.push(valueItems[i]);
    }
    return gridCard;
  }
}

                        

value-img-1.jpg

value-img-2.jpg

0