Проблема

Стили не обновляются при изменении last-child из-за динамического добавления дополнительных элементов с помощью JavaScript.

Примере

Нажмите «Добавить больше блоков» во фрагменте ниже. При добавлении новых блоков четвертый элемент .block («Тестовый блок 4») не будет иметь нижней красной границы, даже если он больше не является последним элементом в #container.

$("#addMore").one("click", function() {
  $("#container").append($("#container").html());
  $(this).remove();
});
.block {
  border-bottom: 1px solid red;
  counter-increment: block;
  margin: 20px 0;
  position: relative;
}
.block:after {
  content: " " counter(block);
}
.block:last-child {
  border-bottom: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
  <div class="block">Test block</div>
  <div class="block">Test block</div>
  <div class="block">Test block</div>
  <div class="block">Test block</div>
</div>
<div id="addMore">Add more blocks</div>

JS Fiddle

Ожидаемое поведение

После нажатия «Добавить дополнительные блоки» все элементы .block должны иметь нижнюю красную рамку , кроме восьмого блока («Тестовый блок 8»).

Браузеры осуществлены

Проверено и не работает в Chrome 55.0.2883.87 m. Ожидаемое поведение, возвращаемое IE 11.0.9600.18538 и Firefox 50.1.0.


Можно ли это решить без :

  • Использование JavaScript (то есть динамическое добавление класса, который удаляет красную границу из последнего элемента)?
  • Реструктурировать CSS, чтобы не использовать last-child (то есть вместо этого использовать first-child и border-top)?
7
Hidden Hobbes 9 Янв 2017 в 14:41

3 ответа

Лучший ответ

Что бы это ни стоило, в качестве обходного пути вы можете заменить псевдокласс last-child на nth-last-child(1), который делает то же самое, что и last-child, но на него не влияет ошибка.

$("#addMore").one("click", function() {
  $("#container").append($("#container").html());
  $(this).remove();
});
.block {
  border-bottom: 1px solid red;
  counter-increment: block;
  margin: 20px 0;
  position: relative;
}
.block:after {
  content: " " counter(block);
}
.block:nth-last-child(1) {
  border-bottom: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
  <div class="block">Test block</div>
  <div class="block">Test block</div>
  <div class="block">Test block</div>
  <div class="block">Test block</div>
</div>
<div id="addMore">Add more blocks</div>
3
Danield 9 Янв 2017 в 12:40

Немного поиграв с этой проблемой, намекает на наличие некоторой ошибки в браузере Chrome.

Однако я заметил, что если мы используем border-top вместо border-bottom, то это работает правильно.

< Сильный > CSS

.block:not(:first-child) {
  border-top: 1px solid red;
}
$("#addMore").one("click", function() {
	$("#container").append($("#container").html());
	$(this).remove();
});
.block {
  counter-increment: block; 
  padding: 20px 0;
  position: relative;
  margin-bottom: 1px;
}
.block:after {
  content: " " counter(block);
}
.block:not(:first-child) {
  border-top: 1px solid red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="container">
  <div class="block">Test block</div>
  <div class="block">Test block</div>
  <div class="block">Test block</div>
  <div class="block">Test block</div>
</div>
<div id="addMore">Add more blocks</div>
1
Mohammad Usman 9 Янв 2017 в 12:08

Я тестировал в Chrome 55.0.2883.87, и это сбивает меня с толку - явно ошибка.

Даже когда я использовал .clone() вместо этого .html(), проблема существует:

$("#container").append($("#container > .block").clone());

Возможное исправление может заключаться в принудительном повторном рендеринге container - я использовал это для повторного рендеринга:

$('#container').hide().show(0);

Смотрите демо ниже:

$("#addMore").one("click", function() {
  $("#container").append($("#container > .block").clone());
  // fix: by forcing re-rendering
  $('#container').hide().show(0);
  $(this).remove();
});
.block {
  border-bottom: 1px solid red;
  counter-increment: block;
  margin: 20px 0;
  position: relative;
}
.block:after {
  content: " " counter(block);
}
.block:last-child {
  border-bottom: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="container">
  <div class="block">Test block</div>
  <div class="block">Test block</div>
  <div class="block">Test block</div>
  <div class="block">Test block</div>
</div>
<div id="addMore">Add more blocks</div>
1
kukkuz 9 Янв 2017 в 12:06