首页 > 解决方案 > Container width based on child flex items

问题描述

I'm trying to make a sidebar that aligns vertically an undetermined number of list items. When the number of items reaches the bottom of the sidebar, they are grouped in columns via flex.

My problem is that I want the width of the sidebar to be 100px wide when closed and when opened, I want it to be the width of the columns. If I use a fixed width for the open state, this happens:

enter image description here

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: !?!?!?!
    }
}

How can i accomplish this? How can a open sidebar and show all the columns?

UPDATE: The height of the sidebar can vary depending on the screen size. I updated the code with the original settings.

UPDATE #2: I tested both solutions, although @itay-gal was a clever CSS only option, it lacked the ability to animate. Since i'm already using JS, i ended up using @pablo-darde solution.

I made a small change in @pablo-darde's so that it could work with a variable height sidebar:

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`;
}

标签: htmlcsslayoutsassflexbox

解决方案


I really attempted to code only with CSS and your code, but without success. I reached the desired result with some JavaScript code. Please, let me know if you can get some more elegant.

Note the css pointer-events: none; property in your li elements. It is very important here. If you want to use href in lis, I believe some refactoring will be needed.

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>


推荐阅读