创建缩小到内容大小的flexbox选项卡

时间:2017-10-02 21:34:57

标签: html css css3 tabs flexbox

我的网页布局使用了flexbox。我正在尝试创建一个选项卡内容组件,该组件将自动调整其选项卡内容的最大值。理想情况下,我也喜欢在各州之间褪色。我正在尝试使用position: absolutemyTabContents1myTabContents2叠加在一起。然后,我使用visibilityopacity选择可见的那个。

所以DOM基本上看起来像这样(为了简单起见,我只显示标签页的内容,而不是用于在它们之间切换的实际用户控件):

<div class='tabContentsList'>
    <div class='tabContentsItem'>
        Contents of first tab
    </div>
    <div class='tabContentsItem activeTab'>           
        Contents of second tab.
    </div>
</div>

我的css是:

.tabContentsList {
    width: 100%;
    height: 100%;
    position: relative;
    display: flex;
    flex-direction: column;
}

.tabContentsItem {
    display: flex;
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    visibility: hidden;
    opacity: 0;
    transition: visibility 0.3s linear, opacity 0.3s linear;
}

.tabContentsItem.activeTab {
    opacity: 1;
    visibility: visible;
}

切换标签时,这会正确显示淡化效果。但是,tabContentsList元素的大小不能包含tabContentsItem元素 - 它基本上将它们视为零大小,因此最终会溢出它们的边界。我已尝试将right: 0替换为width: 100%等,但这没有用。如果你另一方面删除了position: absolute,那么容器会扩展以容纳两个标签的内容,但定位显然是不正确的 - 为隐形标签留下了一个空白区域。显然,flexboxposition: absolute之间存在已知冲突。

那么有另一种方法来实现这一目标吗?例如,是否有另一种方法来覆盖不使用position: absolute且Flexbox会尊重的两个选项卡内容?如果它可以工作,这似乎是一个有用的工具。 谢谢你的任何想法。

2 个答案:

答案 0 :(得分:1)

一般而言,由于绝对定位会使元素无法流动,因此很难根据内容创建适当大小的解决方案,并且很可能需要使用脚本。

另一种选择是使用transform代替定位,可以使标签内容元素的大小相等。
另一种选择是使用负边距代替,对于定位,可以使标签内容元素的大小相等。

此处设置display: flex / tabs上的tabscontent,默认为align-items的{​​{1}}会保持同等效率。

stretch将告诉flex: 0 0 100%填充其父级宽度,然后使用 tabcont1/2/3 负边距,我们可以撤回translateX()在位置。

注意,由于转换后的元素上的tabcont2/3在动画期间来回移动文本,在Chrome中比其他浏览器更明显,我转而使用负边距。当我找到避免这种情况的方法时,我会使用这两种解决方案进行更新。

Stack snippet

&#13;
&#13;
transition
&#13;
.tabs-wrapper {
  width: 80%;
  margin: 0 auto;
}

.tabs-wrapper input {
  display: none;
}

.tabs-wrapper > div {
  display: flex;
}

.tabs-wrapper .tabs > label {
  padding: 5px;
  border: 1px solid lightgray;
  box-sizing: border-box;
  cursor: pointer;
}

.tabs-wrapper .tabscontent {
  padding: 5px;
  border: 1px solid lightgray;
}

.tabs-wrapper .tabscontent > div {
  flex: 0 0 100%;
  opacity: 0;
  transition: opacity .5s;
}

/*.tabs-wrapper .tabscontent > div:nth-child(2) {
  transform: translateX(-100%);
}
.tabs-wrapper .tabscontent > div:nth-child(3) {
  transform: translateX(-200%);
}*/

.tabs-wrapper .tabscontent > div:nth-child(n+2) {
  margin-left: -100%;
}

.tabs-wrapper input:nth-child(1):checked ~ .tabs label:nth-child(1),
.tabs-wrapper input:nth-child(2):checked ~ .tabs label:nth-child(2),
.tabs-wrapper input:nth-child(3):checked ~ .tabs label:nth-child(3) {
  background: lightblue;
}

.tabs-wrapper input:nth-child(1):checked ~ .tabscontent > div:nth-child(1),
.tabs-wrapper input:nth-child(2):checked ~ .tabscontent > div:nth-child(2),
.tabs-wrapper input:nth-child(3):checked ~ .tabscontent > div:nth-child(3) {
  opacity: 1;
}
&#13;
&#13;
&#13;

如果有人无法使用Flexbox,则您不需要

&#13;
&#13;
<div class="tabs-wrapper">
  <input id="tab1" type="radio" name="tab" checked>
  <input id="tab2" type="radio" name="tab">
  <input id="tab3" type="radio" name="tab">
  
  <div class="tabs">
    <label for="tab1">Tab 1</label>
    <label for="tab2">Tab 2, which is longer</label>
    <label for="tab3">Tab 3</label>
  </div>

  <div class="tabscontent">
    <div class="tabcont1">Content 1</div>
    <div class="tabcont2">Content 2,<br>which is higher<br>than 1 and 3</div>
    <div class="tabcont1">Content 3</div>
  </div>
</div>
&#13;
.tabs-wrapper {
  width: 80%;
  margin: 0 auto;
  overflow: hidden;
}

.tabs-wrapper input {
  display: none;
}

.tabs-wrapper .tabs > label {
  display: inline-block;
  padding: 5px;
  border: 1px solid lightgray;
  box-sizing: border-box;
  vertical-align: top;
  cursor: pointer;
}

.tabs-wrapper .tabscontent {
  padding: 5px;
  border: 1px solid lightgray;
  white-space: nowrap;
}

.tabs-wrapper .tabscontent > div {
  display: inline-block;
  width: 100%;
  opacity: 0;
  transition: opacity .5s;
  white-space: normal;
  vertical-align: top;
}

/*.tabs-wrapper .tabscontent > div:nth-child(2) {
  transform: translateX(-100%);
}
.tabs-wrapper .tabscontent > div:nth-child(3) {
  transform: translateX(-200%);
}*/

.tabs-wrapper .tabscontent > div:nth-child(n+2) {
  margin-left: -100%;
}

.tabs-wrapper input:nth-child(1):checked ~ .tabs label:nth-child(1),
.tabs-wrapper input:nth-child(2):checked ~ .tabs label:nth-child(2),
.tabs-wrapper input:nth-child(3):checked ~ .tabs label:nth-child(3) {
  background: lightblue;
}

.tabs-wrapper input:nth-child(1):checked ~ .tabscontent > div:nth-child(1),
.tabs-wrapper input:nth-child(2):checked ~ .tabscontent > div:nth-child(2),
.tabs-wrapper input:nth-child(3):checked ~ .tabscontent > div:nth-child(3) {
  opacity: 1;
}
&#13;
&#13;
&#13;

更新

以下是更新的Flexbox版本,其中<div class="tabs-wrapper"> <input id="tab1" type="radio" name="tab" checked> <input id="tab2" type="radio" name="tab"> <input id="tab3" type="radio" name="tab"> <div class="tabs"> <label for="tab1">Tab 1</label><!-- --><label for="tab2">Tab 2, which is longer</label><!-- --><label for="tab3">Tab 3</label> </div> <div class="tabscontent"> <div class="tabcont1">Content 1</div><!-- --><div class="tabcont2">Content 2,<br>which is higher<br>than 1 and 3</div><!-- --><div class="tabcont1">Content 3</div> </div> </div>显示为弹性列容器,并且container设置为align-items,它实际上是基于flex-start的大小关于内容。

每个项目仍然会比实际内容宽一些,并且需要具有相同的宽度,以便可以使用负边距(或tabcont1/2/3)将它们左对齐定位。

Flexbox用于调整大小的逻辑来自此帖子Flexbox in IE doesn't set item widths correctly

因此,最终要使每个项目在视觉上正确呈现,并且额外的包装器(此处为translate)用于填充和边框。

为了能够对此进行更优化,因为需要脚本。

&#13;
&#13;
span
&#13;
.tabs-wrapper {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
}

.tabs-wrapper input {
  display: none;
}

.tabs-wrapper > div {
  display: flex;
}

.tabs-wrapper .tabs > label {
  padding: 5px;
  border: 1px solid lightgray;
  box-sizing: border-box;
  cursor: pointer;
}

.tabs-wrapper .tabscontent {
}

.tabs-wrapper .tabscontent > div {
  width: 100%;
  opacity: 0;
  transition: opacity .5s;
  display: flex;
}

.tabs-wrapper .tabscontent > div > span {
  display: inline-block;
  padding: 5px;
  border: 1px solid lightgray;
}

/*.tabs-wrapper .tabscontent > div:nth-child(2) {
  transform: translateX(-100%);
}
.tabs-wrapper .tabscontent > div:nth-child(3) {
  transform: translateX(-200%);
}*/

.tabs-wrapper .tabscontent > div:nth-child(n+2) {
  margin-left: -100%;
}

.tabs-wrapper input:nth-child(1):checked ~ .tabs label:nth-child(1),
.tabs-wrapper input:nth-child(2):checked ~ .tabs label:nth-child(2),
.tabs-wrapper input:nth-child(3):checked ~ .tabs label:nth-child(3) {
  background: lightblue;
}

.tabs-wrapper input:nth-child(1):checked ~ .tabscontent > div:nth-child(1),
.tabs-wrapper input:nth-child(2):checked ~ .tabscontent > div:nth-child(2),
.tabs-wrapper input:nth-child(3):checked ~ .tabscontent > div:nth-child(3) {
  opacity: 1;
}
&#13;
&#13;
&#13;

答案 1 :(得分:1)

如果您考虑display:grid而不是flex,您可以将每个标签堆放在同一个位置,并根据最宽和最高的尺寸对它们进行调整:

&#13;
&#13;
#tabsthing {
  display: grid;
  grid-template-areas: "tab  . ";
  grid-template-columns: auto 1fr;
}

a {
  grid-area: tab;
}


/* make up for demo purpose */

a:hover {
  opacity: 0;
}
a {
  border: solid;
  padding: 1em;
  background: turquoise;
  transition: 1s;
  opacity: 0.5;
}

a+a {
  background: tomato;
  text-align: right;
}

a:last-of-type {
  background: yellow;
}
&#13;
<div id="tabsthing">
  <a href="#one">One of three<br/>next line</a>
  <a href="#two">second of three</a>
  <a href="#three"> third of a test about lenght</a>
</div>
&#13;
&#13;
&#13;

https://codepen.io/gc-nomade/pen/pWWQVN

免责声明:这可能是一个专门的javascript工作,毕竟是可靠的。