Mystery space created above row when removing the content inside of one item

坚强是说给别人听的谎言 提交于 2020-01-02 07:32:48

问题


I have a grid with some items, and when I click any item I move the content of that item to a modal.

The modal works great, but when I remove the content from the item, a space appears above the item.

I know that a way around this problem could be using a flexbox, which works fine, but I want to understand what is going on here.

Something that could be key here is that each item has 3 children.

I use position: absolute in two of them, and the other one stays with the default position.

If I use position: absolute in all the children, the problem is fixed.

What is the difference?

When I click the item the content disappears, so how can the result be different depending on the content?

Here's a JSFiddle showing the problem.

Basically, the structure is the following:

HTML

<div class="context">
    <div class="grid">
        <div class="item">
            <div class="cover">  // has position: absolute
                <h1>Title</h1>
            </div>
            <div class="img-wrapper">  // has position: absolute
                <img/>
            </div>
            <div class="description">  // doesn't have a position defined
                <p>Description...</p>
            </div>
        <div class="item">
            // item content
        </div>
    </div>
</div>

I have a total of 8 items, that are wrapped in two rows of 4 items each.

CSS

The CSS to achieve that is the following:

.grid {
  margin-top: 100px;
  font-size: 0; // to get all the items together
  border: 1px solid red;
}

.item {
  width: calc(100% / 4);
  height: 100px;
  position: relative;
  display: inline-flex;
}

.description {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  top: 0;
  bottom: 0;
}

.img-wrapper {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
}

img {
  height: 100%;
  width: auto;
  display: block;
  margin: auto;
}

.cover {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%;
  display: flex;
  justify-content: center;
  align-items: center;
}

Note: The JSfiddle example has more CSS for styling, but the base is the same, and the problem still appears with the code above.

JavaScript

Finally, the JS to move the content to the modal div is the following:

let $itemNode;
let $itemContent;

$().ready(args => {
  // Cache the modal node
  let $modal = $('#modal');

  $('.item').click(function() {
    // First cache the item and content
    // to put it back when needed
    $itemNode = $(this);
    $itemContent = $(this).children();

    // Hides the item
    $itemNode.css({visibility: 'hidden'});

    // Transfer project content to the modal
    $itemContent.appendTo($modal);
  });

});

回答1:


Solutions

I know that a way around this problem could be using a flexbox...

That is correct. Making the parent of the items a flex container solves the problem:

.grid {
  display: flex;     /* new */
  flex-wrap: wrap;   /* new */
  margin-top: 100px;
  font-size: 0;
  border: 1px solid red;
}

revised fiddle

Something that could be key here is that each item has 3 children. I use position: absolute in two of them, and the other one stays with the default position. If I use position: absolute in all the children, the problem is fixed.

Also, correct. By removing the third div from the normal flow of the document, the problem is resolved.

Explanation

Each item in the grid, before any scripting gets involved and items are removed, is artificially positioned.

In other words, in their initial state, the content of the items (the three child divs) are shifting each item to a place where they would otherwise not be. But when the script removes those child divs, each item moves to where it should be.

As you suspected, the problem lies in the third child div of each grid item (.description).

If you simply apply visibility: hidden to the grid item – without removing the child divs – the layout doesn't break.

But with your script, you're not only adding visibility: hidden, you're also removing the child divs.

The first two divs (.cover and .img-wrapper) never cause a problem. They are absolutely positioned, so they're already removed from the normal flow.

However, the third div (.description) is an in-flow child.

This div contains two p children ("Description for this item X" and "More info"). When either of these children is removed, that's when layout breaks.

This is because – for a reason I haven't yet determined – this div was suppressing vertical-align: baseline on the parent, which is an inline-level element and, therefore, gets that vertical-align setting by default.

When the script removes the div, baseline alignment is restored to the parent, shifting it up and, therefore, creating the gap.


EDIT:

As @Kukkuz mentioned an answer, using values other than baseline for vertical-align also solves the problem.




回答2:


Use vertical-align: top to item and you can get rid of the mystery space when the contents of any item is empty. This happens because the grid items are inline (inline-flex).

Note that vertical-align applies to all inline-level and table-cell elements and is used to vertically align inline level elements- see the doc here.

Change inline-flex to inline-block and you can see about the same behavior. Toggle vertical-align in the below snippet and check for yourself:

.context {
  text-align: center;
  height: 400px;
  border: 1px solid black;
}
#modal {
  display: none
}
.grid {
  margin-top: 100px;
  font-size: 0;
  border: 1px solid red;
}
.item {
  width: calc(100% / 4);
  height: 100px;
  transform-origin: center;
  position: relative;
  display: inline-flex;
  transition: box-shadow .3s, transform .3s;
  font-size: 1em;
  vertical-align: top;
}
.description {
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  top: 0;
  bottom: 0;
  z-index: 100;
  opacity: 0;
  background-color: rgba(0, 0, 0, 0.6);
  color: white;
  padding: 20px;
  transition: opacity .3s;
}
.img-wrapper {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;
  background-color: white;
}
img {
  height: 100%;
  width: auto;
  display: block;
  margin: auto;
}
.cover {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%;
  z-index: 1000;
  cursor: pointer;
  opacity: 1;
  display: flex;
  justify-content: center;
  align-items: center;
  font-weight: bold;
  text-align: center;
  color: white;
  transition: transform .3s, opacity .3s;
}
.cover-red {
  background-color: #ff9f80;
}
.cover-green {
  background-color: #66cc66;
}
.cover-blue {
  background-color: #809fff;
}
.cover-yellow {
  background-color: #ffff80;
}
.cover-mag {
  background-color: hsl(338, 95%, 70%);
}
.cover-cyan {
  background-color: hsl(214, 100%, 65%);
}
.item:hover {
  box-shadow: 0 0 6px 3px rgba(0, 0, 0, 0.3);
  z-index: 1100;
  transform: scale(1.02);
}
.item:hover .cover {
  opacity: 0
}
<div class="context">
  <div class="grid">
    <div class="item">


    </div>

    <div class="item">
      <div class="cover cover-cyan">
        <h1>Title 2</h1>
      </div>
      <div class="img-wrapper">
        <img src="http://rs415.pbsrc.com/albums/pp236/Keefers_/Keffers%20Animals/funny-cats-a10.jpg~c200">
      </div>
      <div class="description">
        <p>Description for item 2</p>
        <p>More info</p>
      </div>
    </div>

    <div class="item">
      <div class="cover cover-mag">
        <h1>Title 3</h1>
      </div>
      <div class="img-wrapper">
        <img src="http://i1.kym-cdn.com/entries/icons/original/000/007/203/nononocat.jpg">
      </div>
      <div class="description">
        <p>Description for item 3</p>
        <p>More info</p>
      </div>
    </div>

    <div class="item">
      <div class="cover cover-green">
        <h1>Title 4</h1>
      </div>
      <div class="img-wrapper">
        <img src="https://media0.giphy.com/media/3o85xoi6nNqJQJ95Qc/200_s.gif">
      </div>
      <div class="description">
        <p>Description for item 4</p>
        <p>More info</p>
      </div>
    </div>

    <div class="item">
      <div class="cover cover-cyan">
        <h1>Title 5</h1>
      </div>
      <div class="img-wrapper">
        <img src="https://media0.giphy.com/media/o0vwzuFwCGAFO/200_s.gif">
      </div>
      <div class="description">
        <p>Description for item 5</p>
        <p>More info</p>
      </div>
    </div>

    <div class="item">
      <div class="cover cover-green">
        <h1>Title 6</h1>
      </div>
      <div class="img-wrapper">
        <img src="http://cdn.thecatsite.com/3/37/200x200px-ZC-379ffbad_anime-cat-cute-cuteness-overload-kitten-Favim_com-350157_large.jpeg">
      </div>
      <div class="description">
        <p>Description for item 6</p>
        <p>More info</p>
      </div>
    </div>

    <div class="item">
      <div class="cover cover-red">
        <h1>Title 7</h1>
      </div>
      <div class="img-wrapper">
        <img src="http://www.officialstarwarscostumes.com/~/media/products/oc/yoda-costumes/pet-yoda-costumes/9935319-yoda-cat-hood-pet-star-wars-costumes-000.ashx?w=200&h=200&bc=ffffff">
      </div>
      <div class="description">
        <p>Description for item 7</p>
        <p>More info</p>
      </div>
    </div>

    <div class="item">
      <div class="cover cover-mag">
        <h1>Title 8</h1>
      </div>
      <div class="img-wrapper">
        <img src="http://adst.org/wp-content/uploads/2014/02/cat-general-120-3-_tplq-200x200.jpg">
      </div>
      <div class="description">
        <p>Description for item 8</p>
        <p>More info</p>
      </div>
    </div>
  </div>
  <div id="modal">
  </div>
</div>

I created a demo with inline-block showing the same behavior. This is a general behavior of inline elements - see below:

.wrapper {
  border: 1px solid;
}
.wrapper > * {
  display: inline-block;
  border: 1px solid;
  height: 100px;
  width: 100px;
}
<div class="wrapper">
  <div></div>
  <div>
    <h1>kjk</h1>
  </div>
</div>



回答3:


This is happening because of using visibility:hidden, visibility:hidden only hides visibility of element, and element still acquires space, you should use display:none; rather than visibility:hidden

https://jsfiddle.net/67w721zq/1/



来源:https://stackoverflow.com/questions/39791663/mystery-space-created-above-row-when-removing-the-content-inside-of-one-item

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!