Вертикальный стек элементов с абсолютным позиционированием с использованием только CSS

#css

#css

Вопрос:

Может быть, уже поздно, но я не могу понять это, хотя это кажется относительно простой проблемой.

У меня есть простая функция jQuery, которая запускается при нажатии кнопки. Он создает элементы и добавляет их в body мой DOM:

 $("#addBlock").click(function(){
    var $block = $("<div class='block'>I'm a block</div>");
    $("body").append($block);
});
  

.block Класс включает в себя абсолютное позиционирование, например:

 .block {
    position: absolute;
    top: 10px;
    right: 10px;
    width: 200px;
    height: 50px;
    background-color: #A6201C;
    color: #fff;
}
  

При каждом нажатии кнопки .block успешно добавляется новый элемент. Однако из-за их абсолютного позиционирования они находятся «поверх» друг друга (по оси z). Я хочу, чтобы каждый элемент отображался под своим предыдущим родственным элементом по вертикали (по оси y).

Я думал, что смогу сделать это с помощью псевдоселектора, подобного :nth-of-type , но на самом деле я не смог этого понять. Я могу добиться того, чего хочу, если есть только два .block элемента, использующие смежный комбинатор родственных элементов:

 .block   .block {
    margin-top: 60px; /*The height of the previous block plus 10px for spacing*/
} 
  

Но это бесполезно, потому что я не знаю, сколько элементов с этим классом будет — это могут быть десятки.

Есть ли способ, которым я могу выполнить это, используя только CSS, или мне нужно будет изменить свой jQuery, чтобы выполнить это?

Здесь есть пример скрипки.

Комментарии:

1. Просто хотите больше контекста, position: absolute это необходимо?

2. Я не знаю, какие у вас ограничения на то, что можно трогать или что нельзя трогать, но вы можете легко это сделать, если у вас просто есть содержащий блок, абсолютная позиция которого и добавляемый вами контент — это просто блоки div, которые естественным образом складываются внутри абсолютно позиционированного содержащего блока jsfiddle.net/a0p4bjn7

3. Вам нужно будет изменить свой CSS или JavaScript. Для решения только для CSS вам нужно будет сделать что-то вроде того, что вы сделали (я думаю nth-child ), и создать столько селекторов, сколько потребуется (вы упомянули десятки). Для JS вам нужно будет выполнить математические вычисления, чтобы вычислить смещение или добавить .block узлы внутри элемента контейнера с абсолютной позицией, примененной к нему (вы можете добавить узел контейнера в HTML или создать его один раз с помощью JS).

Ответ №1:

Вместо этого попробуйте добавить элементы блока в родительский div с абсолютным позиционированием:

 $("#addBlock").click(function() {
  var $block = $("<div class='block'>I'm a block</div>");
  $("#blocks").append($block);
});  
 body {
  background: #fff;
  padding: 20px;
}

#blocks {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 200px;
}

.block {
  height: 50px;
  background-color: #A6201C;
  color: #fff;
}  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="addBlock">Add Block</button>
<div id="blocks">

</div>  

Ответ №2:

Вы можете либо обработать немного CSS-логики внутри jQuery

 let numberOfBlocks = 0;

$("#addBlock").click(function(){
  var $block = $("<div class='block'>I'm a block</div>");
  $block.css('top', numberOfBlocks * 60)
  $("body").append($block);
  numberOfBlocks  ;
});  
 body {
  padding: 20px;
}

.block {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 200px;
  height: 50px;
  background-color: #A6201C;
  color: #fff;
}  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="addBlock">Add Block</button>  

Или создайте контейнер с абсолютным позиционированием:

 $("#addBlock").click(function(){
  var $block = $("<div class='block'>I'm a block</div>");
  $("#blockContainer").append($block);
});  
 body {
  padding: 20px;
}

#blockContainer {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 200px;
}

.block {
  height: 50px;
  background-color: #A6201C;
  color: #fff;
  margin-bottom: 10px;
}  
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="blockContainer"></div>
<button id="addBlock">Add Block</button>  

Ответ №3:

Это вариант существующих ответов и комментариев.

Ниже я показываю, как создать и добавить элемент контейнера, который будет располагаться абсолютно, а не отдельные элементы. Хотя вы могли бы быстро подсчитать количество элементов, которые вы добавили на страницу без контейнера, и добавить уникальное top значение для каждого. Наличие контейнера является более чистым, модульным и поддерживаемым, если стили или расположение списка когда-либо меняются.

В приведенном ниже примере также используется ванильный синтаксис JS, синтаксис ES6 и немного BEM.

 ( () => {

  function createBlockListItem( content ) {
   
    const block = document.createElement( 'div' );
   
    block.classList.add( 'block-list__item' );
    block.textContent = content;
   
    return block;
   
  }

  const addBlockBtn       = document.querySelector( '#add-block' );
  const blockList         = document.createElement( 'div' ); // Container element.  
  let   blockListAppended = false;
  
  blockList.classList.add( 'block-list' );  
  
  addBlockBtn.addEventListener( 'click', function ( e ) {
  
    if ( !blockListAppended ) {
      document.body.appendChild( blockList );
      blockListAppended = true;
    }
    
    blockList.appendChild( createBlockListItem( 'I am a block!' ) );
    
  } );

} )();  
 body {
  margin: 0;
}

.block-list {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 200px;
}

.block-list__item {
  height: 50px;
  color: #fff;
  background-color: #A6201C;
}

.block-list__item   .block-list__item {
  margin-top: 10px;
}  
 <button id="add-block">Add Block</button>