使用负边距来控制弹性框中的空间

时间:2016-08-19 19:34:11

标签: javascript jquery html css flexbox

我一直在阅读灵活盒子,以解决我一直遇到的问题。我读过/用作问题研究的主要文章是this

我最近在thisthis问题中提出了这个主题,感谢@ Michael_B的帮助,确定了如何将元素居中(在本例中为{ {1}})在弹性框中,只要弹性框中始终只有三个弹性项(在此布局中:<h2>)。

我想扩展这些要点,因为我意识到如果有更多或(更实际)少于3个灵活项目,可能会有一个解决方案可以解决。

它涉及使用边距。如果在弹性项目上使用<div><h2><div>,则它会将项目放在主轴上(请参阅下图,了解弹性框的工作原理)。

&#13;
&#13;
margin: auto;
&#13;
img {
 width: 100%;
 height: 100%;
}
&#13;
&#13;
&#13;

(这是我弄清楚如何获得下拉照片的最佳方式......)

根据我的理解,使用<img src="http://i.stack.imgur.com/9Oxw7.png" alt="flex-box demo" />是交叉轴margin: auto属性的当前对应物。

因此,可以通过以下方式将弹性项目置于弹性框中:

&#13;
&#13;
align-self
&#13;
$(document).on('click', 'button', function(e) {
  $this = $(this);
  if ($this.attr('id') === 'button1') {
    $('h2').parent().attr("class", "");
    $('h2').attr("class", "toggle1");
  }
  if ($this.attr('id') === 'button2') {
    $('h2').parent().attr("class", "");
    $('h2').attr("class", "toggle1");
  }
  if ($this.attr('id') === 'button3') {
    $('h2').parent().attr("class", "toggle3");
    $('h2').attr("class", "");
  }
  if ($this.attr('id') === 'button4') {
    $('h2').parent().attr("class", "toggle4");
    $('h2').attr("class", "");
  }
  if ($this.attr('id') === 'button0') {
    $('h2').parent().attr("class", "");
    $('h2').attr("class", "");
  }
});
&#13;
div:not(.cont),
div:not(.cont) * {
  border: 1px dotted red;
}
div {
  align-items: center;
  display: flex;
}
button {
  margin: 16px;
}
.toggle1 {
  margin: auto;
}
.toggle2 {
  flex: 1;
}
.toggle3 {
  justify-content: center;
}
.toggle4 {
  justify-content: space-between;
}
&#13;
&#13;
&#13;

正如您从上面的代码段中看到的那样,只有在<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script> <div> <h2>I'm an h2</h2> </div> <div> <span>I'm a span!</span> <h2>I'm an h2</h2> <span>I'm a span!</span> </div> <div> <span>I'm a span!</span> <span>I'm a span!</span> <h2>I'm an h2</h2> <span>I'm a span!</span> <span>I'm a span!</span> </div> <div class="cont"> <button id="button0">clear</button> <button id="button1">margins</button> <button id="button2">flex-grow</button> </div> <div class="cont"> <button id="button3">justify-content: center <br />(on parent)</button> <button id="button4">justify-content: space-around <br />(on parent)</button> </div>的每一侧都有相同数量的弹性项目时它才有效(并且您还可以看到<h2>不起作用只有一个对象)。

  

但是,如果您试图居中的对象的每一侧都存在不平衡的弹性项目数量会怎样? - 当然,您可以在其中放置空白元素并使用justify-content: space-around,但这看起来有点黑客。

我的想法是利用负边际。我读了一篇很棒的文章(here)关于使用负边距以及如何将对象拉向它们等等(另外,甚至w3表示它们是合法的代码 - 而不是hacky)。

我的想法是将flex: 1;设置为<h2>然后以某种方式(我强调以某种方式,就像我一直在做的所有研究一样,我开始失去希望.. 。)取任何兄弟flex-item的宽度,并从margin: auto; ...声音hacky否定,并希望有一种方法可以在没有JS / jQuery或CSS编译器的情况下完成。

  

是否有人知道如何在弹性项目的边缘上否定同一个弹性框中兄弟弹性项目的宽度?

谢谢。

P.S./UPDATE

使用<h2> margin: auto;属性可能有办法实现此目的;但是,我所做的所有测试都没有产生任何结果......也许其他人已经成功使用这种方法了?

5 个答案:

答案 0 :(得分:2)

一种方法是将中心元素从正常的弯曲流中取出。 通过将其绝对定位在容器内部是可能的。 这样做的缺点是Flex容器不再考虑绝对定位元素的高度。

codepen

.container {
  position: relative;
  display: flex;
  width: 500px;
  justify-content: flex-start;
  align-items: center;
  outline: 1px solid blue;
}

.item {
  flex: 0 0 auto;
  outline: 1px solid red;
  margin: 0;
}

.item--center {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
}

.item--right {
  margin-left: auto;
}
<div class="container">
  <span class="item">I'm a span!</span>
  <span class="item">I'm a span!</span>
  <h2 class="item item--center">I'm an h2</h2>
  <span class="item item--right">I'm a span!</span>
</div>

答案 1 :(得分:1)

我设置了一种处理这个

的hacky方法
  1. 制作柔性容器包装
  2. 添加一个伪元素以强制设置
  3. 的换行符
  4. 添加排序属性,以便在第一行中只有中心元素,后跟强制包裹的伪
  5. 使第二行的跨度转到行的结尾和
  6. 做一些转换技巧,使真正的2行显示为一行。
  7. 当然,中心元素以自动边距为中心
  8. 代码段中的第一个容器像往常一样居中作为比较。 第二个容器在左侧比在右侧更多元素,但工作正常:

    div {
      display: flex;
      background-color: lemonchiffon;
      margin-top: 10px;
    }
    
    h2 {
      margin: auto;
    }
    
    span {
      border: solid 1px red;
      padding: 3px;
    }
    
    .container {
      flex-wrap: wrap;
      transform: scaleY(0.5);
    }
    .container:after {
      content: "";
      height: 0px;
      width: 100%;
      flex-shrink: 1;
      background-color: green;
      order: 10;
    }
    
    .container span {
      transform-origin: center top;
      transform: translateY(-100%) scaleY(2);
      position: relative;
      order: 20;
    }
    
    .center {
      transform-origin: center top;
      transform: scaleY(2) ;
    }
    .center ~ span {
      order: 30;
    }
    
    .center + span {
      margin-left: auto;
    }
    <div>
      <span>I'm a span!</span>
      <span>I'm a span!</span>
      <h2>I'm an h2</h2>
      <span>I'm a span!</span>
      <span>I'm a span!</span>
    </div>
    <div class="container">
      <span>I'm a span!</span>
      <span>I'm a span!</span>
      <span>I'm a span!</span>
      <h2 class="center">I'm an h2</h2>
      <span>I'm a span!</span>
      <span>I'm a span!</span>
    </div>

答案 2 :(得分:1)

我不太明白,为什么不简单地使用justify-content: center;如下:

div{
  align-items: center;
  display: flex;  
  justify-content: center;
}
<div>
  <h2>I'm an h2</h2>
</div>

答案 3 :(得分:1)

解决方案1:否定margin-top

  • 不涉及定位(虽然改变了HTML结构)。
  • 隐藏原生展示h2并将其设置为flex: 1;,以便为居中h2留出空间。
  • 居中h2会将原始的h2替换为负margin-top

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
div {
  display: flex;
  flex-flow: row wrap;
  background: gainsboro;
}
div h2 {
  flex: 1;
  color: transparent;
}
h2.center {
  color: black;
  text-align: center;
  background: transparent;
  margin-top: -28px;
}
span {
  border: 1px solid gray;
  display: flex;
  justify-content: flex-start;
  align-items: center;
}
<div>
  <span>I'm a span!</span>
  <span>I'm a span!</span>
  <h2>I'm an h2</h2>
  <span>I'm a span!</span>
</div>
<h2 class="center">I'm an h2</h2>

解决方案2: absolute position

  • 居中h2设置为absolute,位于flex h2之上。
  • HTML结构被更改。

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
div {
  display: flex;
  flex-flow: row wrap;
  background: gainsboro;
}
div h2 {
  flex: 1;
  color: transparent;
}
h2.center {
  color: black;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  text-align: center;
  line-height: 28px;
}
span {
  border: 1px solid gray;
  display: flex;
  justify-content: flex-start;
  align-items: center;
}
<div>
  <span>I'm a span!</span>
  <span>I'm a span!</span>
  <h2>I'm an h2</h2>
  <span>I'm a span!</span>
</div>
<h2 class="center">I'm an h2</h2>

解决方案3: absolute + translate

  • HTML结构未被更改。
  • 整体代码最短,最小,但值得注意。

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
div {
  display: flex;
  justify-content: flex-start;
  background: gainsboro;
  position: relative;
  width: 100%;
}
div h2 {
  position: absolute;
  left: 50%;
  transform: translate(-50%, 0);
  line-height: 20px;
}
span {
  border: 1px solid gray;
}
div h2 + span {
  margin-left: auto;
}
<div>
  <span>I'm a span!</span>
  <span>I'm a span!</span>
  <h2>I'm an h2</h2>
  <span>I'm a span!</span>
</div>

答案 4 :(得分:0)

所以,只是偶然发现了这个问题。我有点不清楚你正在尝试做什么,但我会尽我所能来构建它。

给定容器内任意数量的元素

  1. 指定一个元素始终位于数组的中心
  2. 保留flex布局
  3. 的使用
  4. 不使用JavaScript
  5. Here's my solution at JSFiddle

    如何运作

    1. 我们通过赋予h2位置,将absolute元素从容器流中分离出来。
    2. 我们将容器元素设置为relative位置,以确保其子元素相对于自身定位。
    3. 我们通过将h2top属性设置为left来告诉50%元素我们想要它在容器元素的中心。
    4. 我们通过在transform: translate(-50%, -50%)上设置h2属性来更正元素的偏移量(由于其跟踪基于左上角序号)。 translate值相对于受影响元素的大小,告诉它将其宽度的50%向左滑动,并将其50%的高度向上滑动。
    5. 我们添加一个&#34;虚拟&#34;元素模仿流中绝对定位的h2顺序。我们为虚拟元素提供了一个维度来保留空间,但您可以轻松添加一些文本或其他值以确保它得到布局。
    6. 我们将虚拟元素的可见性设置为hidden。在元素上使用visibility: hidden会将其隐藏在显示位置,但仍会在文档流中保留其空间。
    7. 在创建这个布局的过程中,我打破了你的例子上的按钮,但是我确实清理了你的JS以使其更具可读性。如果按钮对您的理解很重要,我很乐意解决它们。

      相关的CSS如下:

      div {
        position: relative;
      }
      
      h2 {
        position:absolute;
        margin: 0;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        line-height: 40px;
      }
      h3.filler {
        height: 40px;
        visibility: hidden;
      }