Фильтрация DOM элементов на JS

Не смог найти ответа в предыдущем вопросе, поэтому перезадаю*

Дамы и господа, прошу совета. В пример кода выложил фильтр, где есть два споллера, которые должны фильтровать коллекцию li.

Если нажать на первый и выбрать класс, то он отфильтрует, когда нажмёшь на пункт второго споллера - всё сработает, как и должно.

Но если мы выберем ещё раз пункт из второго споллера, то список полностью обнулится, так как выборка делается из существующего списка. Если я сделаю, чтобы он обновлял список, как в первом споллере, то он перестанет фильтровать на основе первого и будет выдавать всегда только список всех предметов не учитывая класс. Как можно пофиксить этот момент? Буду крайне признателен за подсказку.

function openCloseFilter() {

  if (document.querySelectorAll(".filter-spoller") !== null) {

    document.querySelectorAll(".filter-spoller").forEach((e) => {

      e.addEventListener("click", (eve) => {

        if (

          !eve.currentTarget.children[1].classList.contains(

            "filter-spoller-active"

          )

        ) {

          const filterBtns = document.querySelectorAll(".filter-spoller");

          for (let i = 0; i < filterBtns.length; i++) {

            const element = filterBtns[i];

            if (element !== undefined) {

              element.classList.remove("filter-spoller-btn-active");

              // element.children[1].classList.remove("filter-spoller-active");

              for (let i = 0; i < element.children.length; i++) {

                const asd = element.children[i];

                asd.classList.remove("filter-spoller-active");

              }

            }

          }

          eve.currentTarget.children[1].classList.add("filter-spoller-active");

          eve.currentTarget.classList.add("filter-spoller-btn-active");

        } else {

          eve.currentTarget.children[1].classList.remove(

            "filter-spoller-active"

          );

          eve.currentTarget.classList.remove("filter-spoller-btn-active");

        }

      });

    });

 

    // console.log(filterSpollers);

  }

}

// eve.currentTarget.children[1].classList.remove("filter-spoller-active");

// eve.currentTarget.classList.remove("filter-spoller-btn-active");

openCloseFilter();



const filterLiCollection = document.querySelectorAll(".exTasksLi");

document.querySelectorAll(".filter-spoller-classes").forEach((e) => {

  e.addEventListener("click", (eve) => {

    let classItem = e.classList[0].split("-")[3];

    sortLis(classItem);

  }),

    false;

});

 

function sortLis(item) {

  filterLiCollection.forEach((e) =>

    e.getAttribute("data-class")

      ? (e.style.display = "block")

      : console.log("q")

  );

  let result = [...filterLiCollection].filter(

    (e) => e.getAttribute("data-class") !== item && e.style.display == "block"

  );

  result.forEach((e) => (e.style.display = "none"));

}

document.querySelectorAll(".filter-spoller-a-subject").forEach((e) =>

  e.addEventListener("click", (eve) => {

    let subjectItem = e.classList[0].split("-")[3];

    sortSubjects(subjectItem);

  })

);

 

function sortSubjects(subjectItem) {

  filterLiCollection.forEach((e) => {

    let result = [...filterLiCollection].filter(

      (e) => e.getAttribute("data-subject") !== subjectItem

    );

    result.forEach((e) => (e.style.display = "none"));

  });

}

 
.ex-tasks {

    @include adaptiveValue('padding-bottom', 104, 64)

}

 

.ex-tasks__rows {

    h1 {

 

        @include adaptiveValue('font-size', 40, 26);

        @include adaptiveValue('margin-top', 104, 64);

        @include adaptiveValue('margin-bottom', 40, 24);

        font-weight: 700;

        line-height: 120%;

    }

    h3 {

        @include adaptiveValue('font-size', 18, 14);

        margin-bottom: rem(24);

        line-height: 140%;

    }

    h2 {

        @include adaptiveValue('font-size', 18, 14);

        margin-bottom: rem(24);

        line-height: 140%;

        transition: transform .3s ease-in-out;

 

        &:hover {

            transform: translateX(5px);

        }

 

        a {

            transition: transform .3s ease-in-out;

 

        }

 

        &:hover {

            a {

 

                color: $mainTif;

            }

        }

 

    }

}

 

.download-file {}

 

.download-link-keeper-ex-tasks {

    margin-left: 32px;

 

    // position: relative;

}

 

.documents-list {

    li {

        h2 {

 

            // margin-left: 12px;

        }

 

        position: relative;

    }

}

 

#doc {

    position: absolute;

    top: -3px;

    left: 0;

 

}

 

.doc-color-brown {

    path {

        stroke: transparent;

        fill: #A9E44D;

    }

}

 

.doc-color-vanilla {

    path {

        stroke: transparent;

        fill: #4D4B43;

    }

}

 

.doc-color-blue {

    path {

        stroke: transparent;

        fill: #25282B;

    }

}

 

.doc-color-white {

    path {

        stroke: transparent;

        fill: #000;

    }

}

 

.doc-color-black {

    path {

        stroke: transparent;

        fill: #fff;

    }

}

 

@media (orientation: landscape) and (max-height: 500px) {

    .documents__rows {

        h2 {

            margin-bottom: 150px;

        }

    }

}

.filter-spollers-keeper {

    margin-bottom: rem(32);

}

#arrow-filter-spoller {

    transition: transform .3s ease-in-out;

    position: absolute;

    right: 32px;

    top: 40%;

    path {

        stroke: $mainTif;

    }

    path{

        stroke: $pointText;

    }

 

}

.filter-spoller {

 

    position: relative;

    background-color: #fff;

    color: $mainText;

    border: 1px solid $pointText;

    border-radius: 10px;

    transition: border-radius .3s ease;

    line-height: 140%;

    padding-top: 8px;

    padding-bottom: 8px;

    padding-left: 18px;

    margin-bottom: rem(8);

    margin-right: rem(8);

    font-weight: 700;

    text-align: left;

    @include adaptiveValue("width", 220, 220);

    height: 40px;

 

        &__title {

            position: absolute;

            left: 20px;

            top: 7px;

            width: 100%;

 

        }

    }

 

.filter-spoller__box {

 

    overflow: hidden;

    transition-duration: .5s;

    z-index: 20;

    position: absolute;

    top: 38px;

    right: -1px;

    left: -1px;

    color: $mainText;

    @include adaptiveValue("font-size", 16, 14);

    font-weight: 400;

    background-color: #fff;

    border-radius: 10px;

    border: 1px solid $pointText;

    max-height: 0;

    opacity: 0;

    transition: max-height .3s ease-in-out, opacity .2s ease, transform .3s ease;

 

    li {

        &:hover {

            font-weight: 700;

            background-color: $bgTif;

            color: $mainTif;

        }

    }

 

}

.filter-spoller-btn-active {

 

    background-color: #fff;

    color: $mainText;

    border-radius: 10px 10px 0 0 ;

    border-bottom: 0px solid #000;

}

.filter-spoller {

 

    &__content {

        border-top: 1px solid #d9d9d9;

    }

 

    &__list {

 

    }

}

.filter-spoller-li {

    padding-left: rem(20);

    &:not(:last-child) {

        border-bottom: 1px solid #D9D9D9;

    }

    padding-top: rem(8);

    padding-bottom: rem(8);

}

 

.filter-spoller-active {

    transition: max-height .7s ease-in-out, opacity .01s ease, transform .3s ease;

    max-height: 700px;

    opacity: 1;

    border-radius: 0 0 10px 10px;

    border-top: 0px solid #fff;

}

#arrow-infra-leap {

    // z-index: 50;

    transition: transform .3s ease-in-out;

    position: absolute;

    // @include adaptiveValue("right", -160, -16);

    right: 32px;

    top: 40%;

    path {

        stroke: $mainTif;

    }

}

.filter-spoller-opacity {

    transition: transform .3s ease, opacity .3s ease;

    transform: translateY(-50px);

    opacity: 0;

}

 

.filter-spoller-a {

    width: 100%;

    height: 100%;

}
<main class="ex-tasks">

    <div class="ex-tasks__container">

        <section class="ex-tasks__rows">

            <h1></h1>

            <h3></h3>

 

                <button class="filter-spoller">

                    <h4 class="filter-spoller__title">Выберите класс </h4>

                    <div class="filter-spoller__box ">

                        <div class="filter-spoller__content">

                            <ul class="filter-spoller__list">

                                <li class="filter-spoller-li"><a class="filter-spoller-a-7-class filter-spoller-classes" href="#">7 класс</a></li>

                                <li class="filter-spoller-li"><a class="filter-spoller-a-8-class filter-spoller-classes" href="#">8 класс</a></li>

                                <li class="filter-spoller-li"><a class="filter-spoller-a-9-class filter-spoller-classes" href="#">9 класс</a></li>

                                <li class="filter-spoller-li"><a class="filter-spoller-a-10-class filter-spoller-classes" href="#">10 класс</a></li>

                            </ul>

                        </div>

                    </div>

                </button>

                <button class="filter-spoller">

                    <h4 class="filter-spoller__title">Выберите предмет </h4>

                    <div class="filter-spoller__box ">

                        <div class="filter-spoller__content">

                            <ul class="filter-spoller__list">

                                <li class="filter-spoller-li"><a class="filter-spoller-a-math-subject filter-spoller-a-subject" href="#">Математика</a></li>

                                <li class="filter-spoller-li"><a class="filter-spoller-a-ruLang-subject filter-spoller-a-subject" href="#">Русский язык</a></li>

                                <li class="filter-spoller-li"><a class="filter-spoller-a-physics-subject filter-spoller-a-subject" href="#">Физика</a></li>

                                <li class="filter-spoller-li"><a class="filter-spoller-a-chemistry-subject filter-spoller-a-subject" href="#">Химия</a></li>

                                <li class="filter-spoller-li"><a class="filter-spoller-a-biology-subject filter-spoller-a-subject" href="#">Биология</a></li>

                                <li class="filter-spoller-li"><a class="filter-spoller-a-informatics-subject filter-spoller-a-subject" href="#">Информатика</a></li>

                            </ul>

                        </div>

                    </div>

                </button>

                
 

            <ul class="documents-list document-list-ex-tasks">

                <li class="exTasksLi" data-stage="1" data-class="7" data-subject="math" data-year="2023">

                    <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="#" class="download-file" download="">I этап / 7 класс / Математика / 2023</a>

                    </h2>

                </li>

                <li class="exTasksLi" data-stage="1" data-class="8" data-subject="math" data-year="2023">

                    <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 8 класс / Математика / 2023</a></h2>

                </li>

                <li class="exTasksLi" data-stage="1" data-class="8" data-subject="ruLang" data-year="2023">

                    <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 8 класс / Русский язык / 2023</a></h2>

                </li>

                <li class="exTasksLi" data-stage="1" data-class="8" data-subject="physics" data-year="2023">

                    <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 8 класс / Физика / 2023</a></h2>

                </li>

                <li class="exTasksLi" data-stage="1" data-class="8" data-subject="chemistry" data-year="2023">
                    <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 8 класс / Химия / 2023</a></h2>

                </li>

                <li class="exTasksLi" data-stage="1" data-class="8" data-subject="biology" data-year="2023">

                    <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 8 класс / Биология / 2023</a>

                    </h2>

                </li>

                <li class="exTasksLi" data-stage="1" data-class="9" data-subject="math" data-year="2023">
                    <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Математика / 2023</a></h2>

                </li>

                <li class="exTasksLi" data-stage="1" data-class="9" data-subject="ruLang" data-year="2023">

                    <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Русский язык / 2023</a></h2>

                </li>

                <li class="exTasksLi" data-stage="1" data-class="9" data-subject="physics" data-year="2023">

                    <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Физика / 2023</a></h2>

                </li>

                <li class="exTasksLi" data-stage="1" data-class="9" data-subject="chemistry" data-year="2023">
                    <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Химия / 2023</a></h2>

                </li>

                <li class="exTasksLi" data-stage="1" data-class="9" data-subject="biology" data-year="2023">

                    <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Биология / 2023</a></h2>

                </li>

                <li class="exTasksLi" data-stage="1" data-class="9" data-subject="informatics" data-year="2023">

                    <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Информатика / 2023</a></h2>

                </li>

                <li class="exTasksLi" data-stage="1" data-class="10" data-subject="math" data-year="2023">

                    <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Математика / 2023</a></h2>

                </li>

                <li class="exTasksLi" data-stage="1" data-class="10" data-subject="ruLang" data-year="2023">
                    <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Русский язык / 2023</a></h2>

                </li>

                <li class="exTasksLi" data-stage="1" data-class="10" data-subject="physics" data-year="2023">

                    <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Физика / 2023</a></h2>

                </li>

                <li class="exTasksLi" data-stage="1" data-class="10" data-subject="chemistry" data-year="2023">
                    <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Химия / 2023</a></h2>

                </li>

                <li class="exTasksLi" data-stage="1" data-class="10" data-subject="biology" data-year="2023">

                    <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Биология / 2023</a></h2>

                </li>

                <li class="exTasksLi" data-stage="1" data-class="10" data-subject="informatics" data-year="2023">

                    <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Информатика / 2023</a></h2>

                </li>

            </ul>

        </section>

    </div>

</main>


Ответы (2 шт):

Автор решения: Hedonist

Вообщем, сделал через классы. Так проще котнролировать ситуацию.

// Получаем все 18 строчек li. Преобразовываем NodeList в массив, чтобы работали функции высшего порядка (filter, forEach, Map, Reduce)
let filterLiCollection = [...document.querySelectorAll(".exTasksLi")];
 
// Здесь мы получаем 10 кнопок, пробегаемся через forEach и ставим слушатель на click.
//Чтобы знать, как поступать с той или иной кнопкой, идентифицировать её, мы получаем класс, который на каждой кнопке свой, он выглядит так (filter-spoller-a-9-class) на кнопках с классами, и так (filter-spoller-a-math-subject) на кнопках с предметами. С помощью split делим строку по дефисам и берём из массива слово/цифру, в зависимости от кнопки.
//С помощью тернарного оператора проверяем этот символ и вызываем функцию, аргументов передавая это значение
document.querySelectorAll(".filter-spoller-a-all").forEach((e) => {
  e.addEventListener("click", (eve) => {
    let partClass = e.classList[0].split("-")[3];
    partClass == "7" ? filterThis("7") : false;
    partClass == "8" ? filterThis("8") : false;
    partClass == "9" ? filterThis("9") : false;
    partClass == "10" ? filterThis("10") : false;
    partClass == "math" ? filterThis("math") : false;
    partClass == "chemistry" ? filterThis("chemistry") : false;
    partClass == "biology" ? filterThis("biology") : false;
    partClass == "informatics" ? filterThis("informatics") : false;
    partClass == "physics" ? filterThis("physics") : false;
    partClass == "ruLang" ? filterThis("ruLang") : false;
  }),
    false;
});


// Это функция, которая принимает число или слова, в зависимости от нажатой кнопки.
const filterThis = (num) => {
//пробегаемся по всему массиву с li элементами
  filterLiCollection.forEach((e) => {
  //Делаем проверку, чтобы ниженаписанная логика относилась только к своим элементам (без этой проверки не робит)
    if (
      num == "math" ||
      num == "chemistry" ||
      num == "biology" ||
      num == "informatics" ||
      num == "physics" ||
      num == "ruLang"
    ) {
    //здесь фильтрация, которая отбирает те элементы, которые не являются нашей целью. Отбираются, чтобы их скрыть
      let ewq = filterLiCollection.filter(
        (filter) => filter.dataset.subject !== num
      );
      // Здесь удаляются display-none ТОЛЬКО с тех элементов, которые относятся непосредственно к выбору предмета. Это позволит нам выбрать класс, который сузит поиск до 5 элементов, потом выбрать предмет и перевыбирать его. Он будет перезаписываться. Без этого, уже после двух кликов по фильтрам лист окажется пустым.
      filterLiCollection.forEach((el) => el.classList.remove("subject-none"));
//Здесь мы получаем текст в споллере, чтобы менять его на текущий предмет
      let subjTitle = document.querySelector(".title-subject");
      num == "math" ? (subjTitle.innerHTML = `Математика`) : console.log("");
      num == "chemistry" ? (subjTitle.innerHTML = `Химия`) : console.log("");
      num == "biology" ? (subjTitle.innerHTML = `Биология`) : console.log("");
      num == "informatics"
        ? (subjTitle.innerHTML = `Информатика`)
        : console.log("");
      num == "physics" ? (subjTitle.innerHTML = `Физика`) : console.log("");
      num == "ruLang"
        ? (subjTitle.innerHTML = `Русский язык`)
        : console.log("");
     //Здесь мы добавляем класс, который будет скрывать те элементы, которые мы не выбирали.
      ewq.forEach((el) => el.classList.add("subject-none"));
      console.log(ewq);
    }
  });
  //Тут всё то же самое, что и в коде выше.
  if (num == "7" || num == "8" || num == "9" || num == "10") {
    filterLiCollection.forEach((el) => el.classList.remove("class-none"));
    let ewq = filterLiCollection.filter(
      (filter) => filter.dataset.class !== num
    );
    document.querySelector(".title-class").innerHTML = `${num} класс`;
    ewq.forEach((el) => el.classList.add("class-none"));
    console.log(ewq);
  }
};

Друзья, если будут вопросы - пишите в комментариях, если будет необходимо - могу добавить html и тд, чтобы было нагляднее, но это - по запросу.

→ Ссылка
Автор решения: Grundy

Проблема в неверном порядке применении фильтра.

Для решения достаточно вынести фильтрацию по всем критериям в одно место. При клике на фильтр просто заполнять нужный критерий и выполнять общую функцию.

В этом случае обработчик клика может выглядеть так:

const filters = {}; // критерии фильтрации - ключ: имя фильтра, значение: проверяемое значение
document.querySelectorAll(".filter-spoller-a").forEach((e) => {
  e.addEventListener("click", (eve) => {
    let [, , , value, criteria] = e.classList[0].split("-"); // получаем из класса фильтр и проверяемое значение
    filters[criteria] = value; // сохраняем в объект
    applyFilter(filters); // фильтруем список
  });
});

Сама фильтрация происходит в applyFilter, где за один проход просто выставляется display:

function applyFilter(filters) {
  filterLiCollection.forEach((e) => { // бежим по элементам списка
    e.style.display = Object.entries(filters).reduce((acc, [criteria, value]) => acc && (!value || e.dataset[criteria] == value), true) // если элемент соответствует критериям
        ? '' // сбрасываем `display`
        : 'none'; // иначе - скрываем
  });
}

Пример:

function openCloseFilter() {
  if (document.querySelectorAll(".filter-spoller") !== null) {
    document.querySelectorAll(".filter-spoller").forEach((e) => {
      e.addEventListener("click", (eve) => {
        if (!eve.currentTarget.children[1].classList.contains(
            "filter-spoller-active"
          )) {
          const filterBtns = document.querySelectorAll(".filter-spoller");
          for (let i = 0; i < filterBtns.length; i++) {
            const element = filterBtns[i];
            if (element !== undefined) {
              element.classList.remove("filter-spoller-btn-active");
              // element.children[1].classList.remove("filter-spoller-active");
              for (let i = 0; i < element.children.length; i++) {
                const asd = element.children[i];
                asd.classList.remove("filter-spoller-active");
              }
            }
          }
          eve.currentTarget.children[1].classList.add("filter-spoller-active");
          eve.currentTarget.classList.add("filter-spoller-btn-active");
        } else {
          eve.currentTarget.children[1].classList.remove(
            "filter-spoller-active"
          );
          eve.currentTarget.classList.remove("filter-spoller-btn-active");
        }
      });
    });
  }
}

openCloseFilter();
const filterLiCollection = document.querySelectorAll(".exTasksLi");
const filters = {};
document.querySelectorAll(".filter-spoller-a").forEach((e) => {
  e.addEventListener("click", (eve) => {
    let [, , , value, criteria] = e.classList[0].split("-");
    filters[criteria] = value;
    applyFilter(filters);
  });
});


function applyFilter(filters) {
  filterLiCollection.forEach((e) => {
    e.style.display = Object.entries(filters).reduce((acc, [criteria, value]) => acc && (!value || e.dataset[criteria] == value), true) ? '' : 'none';
  });
}
.ex-tasks {
  @include adaptiveValue('padding-bottom', 104, 64)
}

.ex-tasks__rows {
  h1 {
    @include adaptiveValue('font-size', 40, 26);
    @include adaptiveValue('margin-top', 104, 64);
    @include adaptiveValue('margin-bottom', 40, 24);
    font-weight: 700;
    line-height: 120%;
  }
  h3 {
    @include adaptiveValue('font-size', 18, 14);
    margin-bottom: rem(24);
    line-height: 140%;
  }
  h2 {
    @include adaptiveValue('font-size', 18, 14);
    margin-bottom: rem(24);
    line-height: 140%;
    transition: transform .3s ease-in-out;
    &:hover {
      transform: translateX(5px);
    }
    a {
      transition: transform .3s ease-in-out;
    }
    &:hover {
      a {
        color: $mainTif;
      }
    }
  }
}

.download-file {}

.download-link-keeper-ex-tasks {
  margin-left: 32px;
  // position: relative;
}

.documents-list {
  li {
    h2 {
      // margin-left: 12px;
    }
    position: relative;
  }
}

#doc {
  position: absolute;
  top: -3px;
  left: 0;
}

.doc-color-brown {
  path {
    stroke: transparent;
    fill: #A9E44D;
  }
}

.doc-color-vanilla {
  path {
    stroke: transparent;
    fill: #4D4B43;
  }
}

.doc-color-blue {
  path {
    stroke: transparent;
    fill: #25282B;
  }
}

.doc-color-white {
  path {
    stroke: transparent;
    fill: #000;
  }
}

.doc-color-black {
  path {
    stroke: transparent;
    fill: #fff;
  }
}

@media (orientation: landscape) and (max-height: 500px) {
  .documents__rows {
    h2 {
      margin-bottom: 150px;
    }
  }
}

.filter-spollers-keeper {
  margin-bottom: rem(32);
}

#arrow-filter-spoller {
  transition: transform .3s ease-in-out;
  position: absolute;
  right: 32px;
  top: 40%;
  path {
    stroke: $mainTif;
  }
  path {
    stroke: $pointText;
  }
}

.filter-spoller {
  position: relative;
  background-color: #fff;
  color: $mainText;
  border: 1px solid $pointText;
  border-radius: 10px;
  transition: border-radius .3s ease;
  line-height: 140%;
  padding-top: 8px;
  padding-bottom: 8px;
  padding-left: 18px;
  margin-bottom: rem(8);
  margin-right: rem(8);
  font-weight: 700;
  text-align: left;
  @include adaptiveValue("width", 220, 220);
  height: 40px;
  &__title {
    position: absolute;
    left: 20px;
    top: 7px;
    width: 100%;
  }
}

.filter-spoller__box {
  overflow: hidden;
  transition-duration: .5s;
  z-index: 20;
  position: absolute;
  top: 38px;
  right: -1px;
  left: -1px;
  color: $mainText;
  @include adaptiveValue("font-size", 16, 14);
  font-weight: 400;
  background-color: #fff;
  border-radius: 10px;
  border: 1px solid $pointText;
  max-height: 0;
  opacity: 0;
  transition: max-height .3s ease-in-out, opacity .2s ease, transform .3s ease;
  li {
    &:hover {
      font-weight: 700;
      background-color: $bgTif;
      color: $mainTif;
    }
  }
}

.filter-spoller-btn-active {
  background-color: #fff;
  color: $mainText;
  border-radius: 10px 10px 0 0;
  border-bottom: 0px solid #000;
}

.filter-spoller {
  &__content {
    border-top: 1px solid #d9d9d9;
  }
  &__list {}
}

.filter-spoller-li {
  padding-left: rem(20);
  &:not(:last-child) {
    border-bottom: 1px solid #D9D9D9;
  }
  padding-top: rem(8);
  padding-bottom: rem(8);
}

.filter-spoller-active {
  transition: max-height .7s ease-in-out, opacity .01s ease, transform .3s ease;
  max-height: 700px;
  opacity: 1;
  border-radius: 0 0 10px 10px;
  border-top: 0px solid #fff;
}

#arrow-infra-leap {
  // z-index: 50;
  transition: transform .3s ease-in-out;
  position: absolute;
  // @include adaptiveValue("right", -160, -16);
  right: 32px;
  top: 40%;
  path {
    stroke: $mainTif;
  }
}

.filter-spoller-opacity {
  transition: transform .3s ease, opacity .3s ease;
  transform: translateY(-50px);
  opacity: 0;
}

.filter-spoller-a {
  width: 100%;
  height: 100%;
}
<main class="ex-tasks">
  <div class="ex-tasks__container">
    <section class="ex-tasks__rows">
      <h1></h1>
      <h3></h3>
      <button class="filter-spoller">
          <h4 class="filter-spoller__title">Выберите класс </h4>
          <div class="filter-spoller__box ">
              <div class="filter-spoller__content">
                  <ul class="filter-spoller__list">
                  <li class="filter-spoller-li"><a class="filter-spoller-a--class filter-spoller-a" href="#">сбросить</a></li>
                      <li class="filter-spoller-li"><a class="filter-spoller-a-7-class filter-spoller-a" href="#">7 класс</a></li>
                      <li class="filter-spoller-li"><a class="filter-spoller-a-8-class filter-spoller-a" href="#">8 класс</a></li>
                      <li class="filter-spoller-li"><a class="filter-spoller-a-9-class filter-spoller-a" href="#">9 класс</a></li>
                      <li class="filter-spoller-li"><a class="filter-spoller-a-10-class filter-spoller-a" href="#">10 класс</a></li>
                  </ul>
              </div>
          </div>
      </button>
      <button class="filter-spoller">
          <h4 class="filter-spoller__title">Выберите предмет </h4>
          <div class="filter-spoller__box ">
              <div class="filter-spoller__content">
                  <ul class="filter-spoller__list">
                  <li class="filter-spoller-li"><a class="filter-spoller-a--subject filter-spoller-a" href="#">сбросить</a></li>
                      <li class="filter-spoller-li"><a class="filter-spoller-a-math-subject filter-spoller-a" href="#">Математика</a></li>
                      <li class="filter-spoller-li"><a class="filter-spoller-a-ruLang-subject filter-spoller-a" href="#">Русский язык</a></li>
                      <li class="filter-spoller-li"><a class="filter-spoller-a-physics-subject filter-spoller-a" href="#">Физика</a></li>
                      <li class="filter-spoller-li"><a class="filter-spoller-a-chemistry-subject filter-spoller-a" href="#">Химия</a></li>
                      <li class="filter-spoller-li"><a class="filter-spoller-a-biology-subject filter-spoller-a" href="#">Биология</a></li>
                      <li class="filter-spoller-li"><a class="filter-spoller-a-informatics-subject filter-spoller-a" href="#">Информатика</a></li>
                  </ul>
              </div>
          </div>
      </button>
      <ul class="documents-list document-list-ex-tasks">
        <li class="exTasksLi" data-stage="1" data-class="7" data-subject="math" data-year="2023">
          <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="#" class="download-file" download="">I этап / 7 класс / Математика / 2023</a>
          </h2>
        </li>
        <li class="exTasksLi" data-stage="1" data-class="8" data-subject="math" data-year="2023">
          <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 8 класс / Математика / 2023</a></h2>
        </li>
        <li class="exTasksLi" data-stage="1" data-class="8" data-subject="ruLang" data-year="2023">
          <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 8 класс / Русский язык / 2023</a></h2>
        </li>
        <li class="exTasksLi" data-stage="1" data-class="8" data-subject="physics" data-year="2023">
          <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 8 класс / Физика / 2023</a></h2>
        </li>
        <li class="exTasksLi" data-stage="1" data-class="8" data-subject="chemistry" data-year="2023">
          <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 8 класс / Химия / 2023</a></h2>
        </li>
        <li class="exTasksLi" data-stage="1" data-class="8" data-subject="biology" data-year="2023">
          <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 8 класс / Биология / 2023</a>
          </h2>
        </li>
        <li class="exTasksLi" data-stage="1" data-class="9" data-subject="math" data-year="2023">
          <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Математика / 2023</a></h2>
        </li>
        <li class="exTasksLi" data-stage="1" data-class="9" data-subject="ruLang" data-year="2023">
          <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Русский язык / 2023</a></h2>
        </li>
        <li class="exTasksLi" data-stage="1" data-class="9" data-subject="physics" data-year="2023">
          <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Физика / 2023</a></h2>
        </li>
        <li class="exTasksLi" data-stage="1" data-class="9" data-subject="chemistry" data-year="2023">
          <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Химия / 2023</a></h2>
        </li>
        <li class="exTasksLi" data-stage="1" data-class="9" data-subject="biology" data-year="2023">
          <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Биология / 2023</a></h2>
        </li>
        <li class="exTasksLi" data-stage="1" data-class="9" data-subject="informatics" data-year="2023">
          <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 9 класс / Информатика / 2023</a></h2>
        </li>
        <li class="exTasksLi" data-stage="1" data-class="10" data-subject="math" data-year="2023">
          <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Математика / 2023</a></h2>
        </li>
        <li class="exTasksLi" data-stage="1" data-class="10" data-subject="ruLang" data-year="2023">
          <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Русский язык / 2023</a></h2>
        </li>
        <li class="exTasksLi" data-stage="1" data-class="10" data-subject="physics" data-year="2023">
          <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Физика / 2023</a></h2>
        </li>
        <li class="exTasksLi" data-stage="1" data-class="10" data-subject="chemistry" data-year="2023">
          <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Химия / 2023</a></h2>
        </li>
        <li class="exTasksLi" data-stage="1" data-class="10" data-subject="biology" data-year="2023">
          <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Биология / 2023</a></h2>
        </li>
        <li class="exTasksLi" data-stage="1" data-class="10" data-subject="informatics" data-year="2023">
          <h2 class="download-link-keeper download-link-keeper-ex-tasks"><a href="" class="download-file" download>I этап / 10 класс / Информатика / 2023</a></h2>
        </li>
      </ul>
    </section>
  </div>
</main>

→ Ссылка