Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chrome not updating styles when last-child changes

Problem

Styles are not being updated when the last-child changes due to extra elements being added dynamically with JavaScript.

Example

Click "Add more blocks" in the snippet below. When the new blocks are added the fourth .block element ("Test block 4") will not have a bottom red border even though it is no longer the last element in #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

Expected behaviour

After clicking "Add more blocks" all .block elements should have a bottom red border except the eighth block ("Test block 8").

Browsers effected

Tested and not working in Chrome 55.0.2883.87 m. Expected behavior returned by IE 11.0.9600.18538 and Firefox 50.1.0.


Can this be resolved without:

  • Using JavaScript (i.e. dynamically adding a class which removes the red border from the last element)?
  • Restructuring the CSS to not use last-child (i.e. using first-child and border-top instead)?
like image 924
Hidden Hobbes Avatar asked Jan 09 '17 11:01

Hidden Hobbes


3 Answers

For what it's worth, as a workaround you could replace the last-child pseudo class with nth-last-child(1) which does exactly the same thing as last-child, but is unaffected by the bug.

$("#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>
like image 178
Danield Avatar answered Nov 20 '22 15:11

Danield


I tested in Chrome 55.0.2883.87 and it baffles me - clearly a bug.

Even when I used .clone() instead on .html() the issue is there:

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

A possible fix might be to force a re-render of container - I used this for the re-render:

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

See demo below:

$("#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>
like image 27
kukkuz Avatar answered Nov 20 '22 14:11

kukkuz


Playing a little bit with this issue hints the presence of some bug in chrome browser.

However I've noticed that if we use border-top instead of border-bottom then it works correctly.

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>
like image 1
Mohammad Usman Avatar answered Nov 20 '22 15:11

Mohammad Usman