Как я могу изменить переполнение css в зависимости от содержимого?

#javascript #html #css

Вопрос:

Я создаю свой собственный раскрывающийся список с помощью CSS. Вы наводите на него курсор, затем под ним появляются некоторые опции, вы выбираете одну из них, и все. Если вариантов слишком много, чтобы поместиться, есть полоса прокрутки. Вы можете увидеть все это здесь: JSFiddle

 let testData = [
    "qwertyuiop",
    "asdfghjkl",
    "zxcvbnm",
    "axdxfcbhdhvhv",
    "äöäööäöääöää",
    "zoinkszoinks",
    "brrrrrrrrrr",
    "gygygygyasdasda",
];

getTestStuff();

function getTestStuff() {
    let content = document.getElementById("content");
    let text = document.getElementById("text");
    for (let group of testData) {
        let div = document.createElement("div");
        div.innerHTML = group;
        div.addEventListener("click", function() { 
            text.innerHTML = group; // update button text
        }, false);

        content.appendChild(div);
    }
}

let dropdown = document.getElementById("dropdown");
let arrow = document.getElementById("arrow");
let content = document.getElementById("content");
dropdown.addEventListener("mouseenter", function () {
    arrow.className = "open";
    content.classList.add("open");
}, false); 

dropdown.addEventListener("mouseleave", function () {
    arrow.className = "closed";
    content.classList.remove("open");
}, false);  
 .dropdown-wrapper {
    height: 40px;
    float: left;
    margin: 0px 5px;
}

.dropdown-wrapper, .dropdown-content {
    width: 300px;
}

.dropdown-wrapper .header {
    width: 100%;
    height: 100%;
    margin: 0;
    background-color: #f1f1f1;
    text-align: center;
    border-radius: 5px;
    font-size: 16px;
    border: 1px solid grey;
    display: table; 
}

.dropdown-wrapper .header span {
      text-align: center;
      vertical-align: middle;
      display: table-cell;
      width: 100%;
}

.dropdown-wrapper .header div span {
    font-size: 20px;
}

.dropdown-wrapper .header div {
    margin-left: -40px;
    width: 40px;
    height: 40px;
    float: right;
    text-align: center;
    display: table;
    position: absolute;
}

.dropdown-content {
    display: none;
    float: none;
    max-height: 300px;
    overflow-x: hidden;
    overflow-y: scroll;
    position: absolute;
    font-size: 16px;
    background-color: #f1f1f1;
    min-width: 0px;
    box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
    z-index: 1;
    margin-right: auto;
    text-align: center;
}

.dropdown-content div {
    color: black;
    float: none;
    padding: 12px 16px;
    text-decoration: none;
    display: block;
    margin-right: -15px;
}

.dropdown-content div:hover {
    background-color: #ddd;
}

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

.dropdown:hover .dropdown-content {
    display: block;
}


#arrow.open {
    -webkit-animation-name: openArrowAnimation;
    -webkit-animation-duration: 0.5s;
    -webkit-animation-iteration-count: 1;
    -webkit-animation-timing-function: ease;
    -webkit-animation-fill-mode: forwards;
}

#arrow.closed {
    -webkit-animation-name: closeArrowAnimation;
    -webkit-animation-duration: 0.5s;
    -webkit-animation-iteration-count: 1;
    -webkit-animation-timing-function: ease;
    -webkit-animation-fill-mode: forwards;
}

@-webkit-keyframes openArrowAnimation {
  from {
    -webkit-transform: rotate(0deg);
  }
  to {
    -webkit-transform: rotate(180deg);
  }
}

@-webkit-keyframes closeArrowAnimation {
  from {
    -webkit-transform: rotate(180deg);
  }
  to {
    -webkit-transform: rotate(0deg);
  }
}

#content.open {
    -webkit-animation-name: openDropdownAnimation;
    -webkit-animation-duration: 0.5s;
    -webkit-animation-iteration-count: 1;
    -webkit-animation-timing-function: ease;
    -webkit-animation-fill-mode: forwards;
}

@-webkit-keyframes openDropdownAnimation {
  from {
    max-height: 0px;
  }
  to {
    max-height: 300px;
  }
} 
  <div class="dropdown-wrapper">
     <div class="dropdown" id="dropdown">
         <div class="header">
             <span id="text">Test Thing</span>
             <div id="arrow"><span>^</span></div>
         </div>
         <div id="content" class="dropdown-content">
         </div>
     </div>
</div> 

Проблема:

  1. Полоса прокрутки появляется во время моей анимации. Что не является проблемой, если оно останется, но когда содержимое подходит, оно снова исчезает.
  2. Когда полосы прокрутки нет, пространство, которое занимала бы полоса прокрутки, не имеет правильного цвета фона, когда я навожу курсор на опцию. Образуется очень уродливый пробел.

Я знаю об overflow: auto; этом, но я все еще использую overflow: scroll; с margin-right: -16px; детьми, потому что моя полоса прокрутки перемещает детей, и у меня есть эта полоса прокрутки только иногда.

Мне нужен какой-то условный взлом CSS, чтобы установить overflow значение скрыто, если нам это не нужно, или использовать JS для изменения margin-right , но попытка проверить высоту родителей после добавления детей дала мне это:

Содержание.высота: не определена

содержание.стиль.высота: пустая строка

Так что я очень запутался в этом.

Комментарии:

1. Я не уверен, о чем вы спрашиваете, поэтому я спрашиваю: вы хотите изменить css с родительского узла в зависимости от содержимого дочернего узла? Это невозможно только с помощью css

2. Я на самом деле не ищу никакого конкретного решения этой проблемы. Я видел некоторые css-хаки, использующие calc () , но я недостаточно понимаю их, чтобы редактировать любое решение, которое я нахожу, в соответствии со своей проблемой.

3. Если вы «не ищете конкретного решения», то этот вопрос выходит за рамки темы.

4. 2. это связано с тем , что вы задаете overflow-y: scroll; , заставляя «заполнитель» для потенциальной полосы прокрутки. Если вы не хотите этого, установите auto вместо этого.

5. «Высота смещения и высота прокрутки равны 0, так как я не определил никакой высоты» — это не причина, причина в том, что вы пытаетесь прочитать их, пока элемент имеет display:none . Элементы с таким стилем вообще не имеют никаких размеров.

Ответ №1:

Я заставил его работать с этим трюком над детьми:

 margin-right: calc(100% - 300px);
 

И установка родителя overflow на auto

Это работает, потому что здесь 100% — это элементы во всю ширину. Без полосы прокрутки 100% составляет 300 пикселей, поэтому поле равно 0. С полосой прокрутки 100% составляет около 290 пикселей, поэтому поле равно примерно -10, поэтому текст остается по центру.

Ответ №2:

Как отметил @CBroe, я не мог достичь высоты своей стихии или детей, потому что это было display: none так, чтобы обойти это:

 let content = document.getElementById("content");
content.style.display = "block";
let height = content.offsetHeight;
content.style.display = "";
 

Удивительно, что такая глупость так хорошо работает. Теперь я могу скрыть полосу прокрутки, когда она мне не нужна, и исправить смещение, которое создает полоса прокрутки, когда она мне нужна:

 if (height < 300) {
    content.style.overflowY = "hidden";
} else {
    content.style.overflowY = "scroll";
    for (let kid of content.children) {
        kid.style.marginRight = "-16px";
    }
}
 

Это решение имеет дополнительный бонус в том, что оно хорошо работает с моей анимацией. Проблема, которую не могло решить единственное решение CSS.