基于子伸缩项目的容器宽度

时间:2018-11-13 20:27:49

标签: html css layout sass flexbox

我正在尝试制作一个垂直对齐的边栏,未确定数量的列表项。当项目数达到侧边栏的底部时,它们将通过flex分组在列中。

我的问题是,我希望在关闭和打开时边栏的宽度为100px宽,我希望它是列的宽度。如果我在打开状态下使用固定宽度,则会发生这种情况:

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

我该怎么做?如何打开侧边栏并显示所有列?

更新:边栏的高度可能会因屏幕尺寸而异。我用原始设置更新了代码。

更新#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`;
}

4 个答案:

答案 0 :(得分:2)

我真的只尝试使用CSS和您的代码进行编码,但是没有成功。我通过一些JavaScript代码达到了预期的结果。拜托,让我知道是否可以再优雅一点。

请注意pointer-events: none;元素中的css li属性。在这里非常重要。如果您想在href s中使用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>

答案 1 :(得分:1)

仅通过CSS关闭。您将无法对打开/关闭进行动画处理。

我的建议是使用一些JavaScript来计算元素并设置所需的宽度,但是,如果您真的不能这样做,可能会有所帮助:

首先设置边栏的高度,然后设置ul以将li包裹在其中。这样会将li设置在正确的位置。

添加overflow: hidden将隐藏除第一列之外的所有内容。

悬停时,我将溢出设置为可见-这样您就可以看到其余li了。

因为我们无法向溢出的部分添加背景,所以我通过在每个div内添加一个li来模拟它。

这几乎可以解决问题。但是,当最后一列未满时,您会在最后一列中看到一个没有背景的空白。

因此,要克服此问题,我向最后一个元素添加了after选择器,并选择了整个ul的高度,并添加了containeroverflow: 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>

答案 2 :(得分:0)

只需一点点Javascript即可轻松完成。您将获得列表项的数量,然后进行一些计算以确定所需的列数,并将该宽度样式应用于边栏。

答案 3 :(得分:-1)

此代码段虽然不漂亮,但可能会给您一些帮助。我在侧边栏上隐藏了一个溢出。将其设置为第一列的宽度。然后将鼠标悬停在侧边栏上,将宽度更改为两列的大小。

.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>