Espace mystère créé au-dessus de la ligne lors de la suppression du contenu d’un élément

J’ai une grid avec certains éléments et lorsque je clique sur un élément, je déplace le contenu de cet élément vers un modal.

Le modal fonctionne très bien, mais lorsque je supprime le contenu de l’élément, un espace apparaît au-dessus de l’élément.

Je sais qu’une solution à ce problème pourrait consister à utiliser une boîte souple, qui fonctionne bien, mais je veux comprendre ce qui se passe ici.

Ce qui pourrait être la clé ici est que chaque article a 3 enfants.

J’utilise position: absolute dans deux d’entre eux, et l’autre rest avec la position par défaut.

Si j’utilise position: absolute dans tous les enfants, le problème est résolu.

Quelle est la différence?

Lorsque je clique sur l’élément, le contenu disparaît. Comment le résultat peut-il être différent en fonction du contenu?

Voici un JSFiddle montrant le problème.

Fondamentalement, la structure est la suivante:

HTML

 
// has position: absolute

Title

// has position: absolute
// doesn't have a position defined

Description...

// item content

J’ai un total de 8 articles, qui sont emballés dans deux rangées de 4 articles chacune.

CSS

Le CSS pour y parvenir est le suivant:

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

Remarque : L’exemple JSfiddle a plus de CSS pour le style, mais la base est la même et le problème persiste avec le code ci-dessus.

JavaScript

Enfin, le JS pour déplacer le contenu vers le div modal est le suivant:

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

Solutions

Je sais qu’un moyen de contourner ce problème pourrait être d’utiliser une boîte flexible.

C’est correct. Faire du parent des articles un conteneur flexible résout le problème:

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

violon révisé

Ce qui pourrait être la clé ici est que chaque article a 3 enfants. J’utilise position: absolute dans deux d’entre eux, et l’autre rest avec la position par défaut. Si j’utilise position: absolute dans tous les enfants, le problème est résolu.

Aussi, corrigez. En supprimant la troisième division du stream normal du document, le problème est résolu.

Explication

Chaque élément de la grid, avant que les scripts ne soient impliqués et les éléments supprimés, est positionné artificiellement.

En d’autres termes, dans leur état initial, le contenu des éléments (les trois divs enfants) déplace chaque élément vers un endroit où il ne serait autrement pas. Mais lorsque le script supprime ces divs enfants, chaque élément se déplace là où il devrait être.

Comme vous le supposiez, le problème réside dans la troisième .description enfant de chaque élément de la grid ( .description ).

Si vous appliquez simplement la visibility: hidden à l’élément de grid – sans supprimer les divs enfants – la mise en page ne se rompt pas.

Mais avec votre script, vous n’ajoutez pas que de la visibility: hidden , vous supprimez également les divs enfants.

Les deux premiers divs ( .cover et .img-wrapper ) ne posent jamais de problème. Ils sont absolument positionnés, ils sont donc déjà retirés du stream normal.

Cependant, la troisième .description ( .description ) est un enfant .description .

Cette div contient deux enfants p (“Description pour cet élément X” et “Plus d’infos”). Lorsque l’un de ces enfants est supprimé, c’est le moment de la mise en page .

En effet, pour une raison que je n’ai pas encore déterminée, cette division supprimait vertical-align: baseline sur le parent, qui est un élément de niveau en ligne et, par conséquent, obtient ce paramètre d’ vertical-align par défaut .

Lorsque le script supprime la div, l’alignement de la ligne de base est restauré sur le parent, ce qui le déplace vers le haut et crée donc un espace.


MODIFIER:

Comme @Kukkuz a mentionné une réponse , l’utilisation de valeurs autres que baseline pour vertical-align résout également le problème.

Utilisez vertical-align: top to item et vous pouvez vous débarrasser de l’ espace mystère lorsque le contenu d’un élément est vide.

Cela est dû au fait que les éléments de la grid sont en inline (inline-flex). Notez que vertical-align s’applique à tous les éléments de niveau ligne et tableau et est utilisé pour aligner verticalement les éléments de niveau ligne – voir la documentation ici .

Changez inline-flex en inline-block et vous pourrez voir le même comportement.

Basculez vertical-align dans l’extrait ci-dessous et vérifiez vous-même:

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

Title 2

Description for item 2

More info

Title 3

Description for item 3

More info

Title 4

Description for item 4

More info

Title 5

Description for item 5

More info

Title 6

Description for item 6

More info

Title 7

Description for item 7

More info

Title 8

Description for item 8

More info

Cela se produit à cause de l’utilisation de la visibility:hidden , visibility:hidden ne masque que la visibilité de l’élément, et l’élément acquiert toujours de l’espace, vous devez utiliser display:none; plutôt que visibility:hidden

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