Ширина контейнера на основе дочерних гибких элементов

Я пытаюсь создать боковую панель, которая выравнивает по вертикали неопределенное количество элементов списка. Когда количество элементов достигает нижней части боковой панели, они группируются в столбцы с помощью гибкости.

Моя проблема в том, что я хочу, чтобы ширина боковой панели была 100 пикселей при закрытии, а при открытии я хочу, чтобы она была шириной столбцов. Если я использую фиксированную ширину для открытого состояния, произойдет следующее:

Ширина контейнера на основе дочерних гибких элементов

HTML:

<nav class = "sidebar">
    <ul>
        <li>
            1
        </li>
        <li>
            2
        </li>
        <li>
            3
        </li>
        <li>
            4
        </li>
        <li>
            5
        </li>       
        <li>
            ...
        </li>       
    </ul>
</nav>

SCSS:

.sidebar {
    background: #ccc;
    width: 100px;

    ul {
        list-style-type: none;
        height: 100vh;

        display: flex;
        flex-wrap: wrap;
        flex-direction: column;
        align-content: flex-start;

        li {
            background: #000;
            height: 80px;
            width: 80px;
        }
    }

    &:hover
    {
        //width: !?!?!?!
    }
}

Как я могу этого добиться? Как можно открыть боковую панель и показать все столбцы?

Обновлено: Высота боковой панели может варьироваться в зависимости от размера экрана. Я обновил код с исходными настройками.

ОБНОВЛЕНИЕ №2: Я тестировал оба решения, хотя @ itay-gal был умным вариантом только для CSS, в нем отсутствовала возможность анимации. Поскольку я уже использую JS, я остановился на решении @ pablo-darde.

Я сделал небольшое изменение в @ pablo-darde, чтобы он мог работать с боковой панелью переменной высоты:

const sidebar = document.querySelector('.sidebar');
const ul = sidebar.querySelector('ul');
const li = ul.querySelector('li');

const showRemainder = () => {
    const ulHeight = ul.clientHeight;
    const liHeight = li.clientHeight;
    const width = ul.clientWidth * Math.ceil(ul.children.length / (ulHeight / liHeight));
    sidebar.style.maxWidth = `${width}px`;
}

Не уверен, почему @Michael_B пометил его как дубликат, похоже, это не тот же вопрос, и я нашел решение только с css

Itay Gal 13.11.2018 23:57

Я пометил его как дубликат, потому что этот вопрос задавался и исследовался много раз раньше. Кроме того, ваш ответ не объясняет проблемы. Он также не объясняет ответ (что на самом деле является обходным путем). Но если вы считаете, что ваш ответ - полезное решение общей проблемы, опубликуйте его в основном (дублирующем) посте. @ItayGal

Michael Benjamin 14.11.2018 00:05

Я подумал, что мы здесь ищем обходные пути, чтобы заставить все работать, даже если это не тривиально и легко :) И я не думаю, что мне нужно объяснять проблему, просто чтобы объяснить, как я ее преодолеваю, и я подробно остановлюсь на своем решение скоро.

Itay Gal 14.11.2018 00:09
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Введение в CSS
Введение в CSS
CSS является неотъемлемой частью трех основных составляющих front-end веб-разработки.
Как выровнять Div по центру?
Как выровнять Div по центру?
Чтобы выровнять элемент <div>по горизонтали и вертикали с помощью CSS, можно использовать комбинацию свойств и значений CSS. Вот несколько методов,...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Travel Booking Angular Template один из лучших Travel & Tour booking template in the world. 30+ валидированных HTML5 страниц, которые помогут...
2
3
1 479
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

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

Обратите внимание на свойство css pointer-events: none; в ваших элементах li. Здесь это очень важно. Если вы хотите использовать href в li, я считаю, что потребуется некоторый рефакторинг.

const sidebar = document.querySelector('.sidebar');
const ul = sidebar.querySelector('ul');

const showRemainder = () => {
  const width = ul.clientWidth * Math.ceil(ul.children.length / 5);
  sidebar.style.maxWidth = `${width}px`;
}

const hideRemainder = () => {
	sidebar.style.maxWidth = '80px';
}

sidebar.addEventListener('mouseover', showRemainder);

sidebar.addEventListener('mouseout', hideRemainder);
.sidebar {
  background: #ccc;
  max-width: 80px;
  width: auto;
  height: 400px;
  overflow: hidden;
  transition: all 0.5s ease;
}

.sidebar ul {
  list-style-type: none;
  height: 400px;
  display: flex;
  padding: 0;
  margin: 0;
  flex-flow: column wrap;
  align-content: flex-start;
}

.sidebar ul li {
  display: flex;
  pointer-events: none;
  justify-content: center;
  align-items: center;
  background: #000;
  height: 80px;
  width: 80px;
  color: #fff;
  box-sizing: border-box;
  border: 1px solid #fff;
}
<nav class = "sidebar">
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        <li>6</li>
        <li>7</li>
        <li>8</li>
        <li>9</li>
        <li>10</li>
        <li>11</li>
        <li>12</li>
        <li>13</li>
    </ul>
</nav>

Это решение работает с переменной высотой? Моя боковая панель может иметь разную высоту в зависимости от размера экрана. Я обновил свой вопрос.

Ricky 14.11.2018 09:56

Ваше решение не работает с боковой панелью переменной высоты, поэтому я немного изменил ваш код. Я обновил свой вопрос, добавив в ваш код изменения.

Ricky 14.11.2018 11:52

Это решение не работает с переменной высотой. Вам нужно изменить какой-то код. Я думаю, вы можете получить высоту lis и добавить ее в расчет.

Pablo Darde 14.11.2018 12:33

Я обновил свой вопрос изменениями, внесенными в ваше решение. Я также отметил ваш ответ как решение моей проблемы.

Ricky 14.11.2018 15:25

Этот фрагмент некрасивый, но может дать вам кое-что, с чем можно поработать. Я скрыл переполнение на боковой панели. Установите ширину вашего первого столбца. Затем при наведении курсора на боковую панель измените ширину на размер обоих столбцов.

.sidebar {
  background: #ccc;
  width: 100px;
  overflow:hidden;
  -webkit-transition: width 1s;
  transition: width 1s;    
}

ul {
  margin-left: -20px;
  list-style-type: none;
  height: 500px;
  display: flex;
  flex-wrap: wrap;
  flex-direction: column;
  align-content: flex-start;
  justify-content: center;
}

li {
  background-color: #000;
  height: 80px;
  width: 80px;
  color: white;
  text-align: center;
}

.sidebar:hover {
  width: 200px;
}
<nav class = "sidebar">
  <ul>
    <li>
      1
    </li>
    <li>
      2
    </li>
    <li>
      3
    </li>
    <li>
      4
    </li>
    <li>
      5
    </li>
    <li>
      6
    </li>
    <li>
      7
    </li>
    <li>
      8
    </li>
    <li>
     9
    </li>
    <li>
     10
    </li>
    <li>
      11
    </li>
    <li>
      12
    </li>    
    
  </ul>
</nav>

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

Подобрался только с помощью CSS. Вы не сможете анимировать открытие / закрытие.

Мое предложение использует небольшой JavaScript для подсчета элементов и установки необходимой ширины, но если вы действительно не можете, это может помочь:

Сначала я установил высоту боковой панели, а затем установил ul так, чтобы li находился внутри. Это установит li в правильное место.

Добавление overflow: hidden скроет все, кроме первого столбца.

при наведении курсора я устанавливаю видимость переполнения, чтобы вы могли видеть остальные li.

поскольку мы не можем добавить фон к той части, которая выходит за пределы, я смоделировал это, добавив div внутри каждого li.

Это почти поможет. НО, когда последний столбец не заполнен, вы увидите пустой промежуток без фона в последнем столбце.

Итак, чтобы преодолеть это, я добавил селектор after к последнему элементу с высотой всего ul и добавил container с overflow: hidden, чтобы скрыть ненужную часть.

Чего может не хватать?

Мы не можем анимировать его, потому что overflow не поддерживает анимацию.

.sidebar {
  list-style-type: none;
  overflow: hidden;
  width: 100px;
  transition: all 1s;
  height: 400px;
  display: flex;
}

.sidebar ul {
  list-style-type: none;
  margin: 0px;
  padding: 0px;
  display: flex;
  flex-wrap: wrap;
  flex-direction: column;
  align-content: flex-start;
}

.sidebar li {
  background-color: #ccc;
  padding: 10px;
}

.sidebar li div {
  background-color: red;
  height: 80px;
  width: 80px;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 32px;
  font-weight: bold;
  position: relative;
}

.sidebar:hover {
  overflow: visible;
}

.sidebar li:last-child div:after{
  height: 400px;
  background-color: #ccc;
  content:"     htr   ";
  position: absolute;
  display: none;
  z-index: -1;
  top: 0px;
  width: 100px;
}

.sidebar:hover li:last-child div:after{
  display: inline-block;
}
.container{
 height: 400px;
 overflow-y: hidden;
}
<div class = "container">
<nav class = "sidebar">
  <ul>
    <li>
      <div>1</div>
    </li>
    <li>
      <div>2</div>
    </li>
    <li>
      <div>3</div>
    </li>
    <li>
      <div>4</div>
    </li>
    <li>
      <div>5</div>
    </li>
    <li>
      <div>6</div>
    </li>
    <li>
      <div>7</div>
    </li>
    <li>
      <div>8</div>
    </li>
    <li>
      <div>9</div>
    </li>
    <li>
      <div>10</div>
    </li>
    <li>
      <div>11</div>
    </li>
    <li>
      <div>12</div>
    </li>
    <li>
      <div>13</div>
    </li>
     <li>
      <div>14</div>
    </li>
  </ul>
</nav>
</div>

Я собираюсь попробовать ваше решение сегодня. Я вернусь с обратной связью.

Ricky 14.11.2018 09:58

Ваше решение работает, но мне действительно нужны анимации. По этой причине я не пометил ваш ответ как ответ. Умная мысль;)

Ricky 14.11.2018 12:05

Другие вопросы по теме