Elements do not move to their correct place until the window is affected?

html5
javascript

#1

I have a button that, when clicked, inserts some HTML onto the page in the form of textareas. Upon the first click of the button, the first textareas appear fine in the places that they should, but when I click the button two or more times the textareas begin appearing in wonky places (some on top of one another, some not adjusting for the ones above, etc.). However, as soon as the browser window is affected in any way (e.g. is windowed or maximized, or the Chrome Developer Tools are brought up with Ctrl+Shift+J) that causes the browser content to redraw, the textareas instantly snap to their correct locations.

So to me, it seems as though my HTML/CSS is perfectly fine, it's just the browser needing to re-draw the content? That's just my hypothesis, though, and I added a function that calls the focus() method after (since that is supposed to force reflow) but that didn't seem to have any effect.

Can anyone answer why this is happening and what I can do to fix it so that the new textareas appear in the correct place every time the button is clicked?


Here is a jsfiddle reproducing the problem: https://jsfiddle.net/eLn1am2k/3/

(can't add screenshots because I'm a new user).


#2

Hi,
A couple of problems I see is your script inserting spans with #IDs' on them. That means you will have more than one element with the same ID, though it is not necessarily the problem your explaining, it is invalid html nonetheless.

but when I click the button two or more times the textareas begin appearing in wonky places (some on top of one another, some not adjusting for the ones above, etc.)

      $("#plus").click(function() {
        $("#plus").before("<br><input type='text' name='Loc' style='position:absolute;left:0;'>");
        var newSpan = "<br><span id='DateSpan" + spanCounter + "' style='position:absolute;left:0;'><input type='text' name='Date'>&nbsp;in&nbsp;</span>";

You are setting those spans as position:absolute with nothing but a <br> tag to separate them. I see that as a bigger problem that may very well be the source of the misplaced spans.

The first thing I would do is remove all your inline styles and absolute positioning. Then set up a solid html structure, then in the CSS set the styles for the new spans your script inserts, and make them classes.

I see you are using the <img> as your click function so you can leave it as AP as the last child in that div.

The following code produces this for me...

It may be better served as a form with a label for the headings, but the following uses divs to get the basic structure in place. You'll need to rework your script a little, something broke on me when changing to classes.

HTH

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
  <title>Test Page</title>
<style>
body {
   background-color: rgb(90, 90, 96);
   font-family: "Lucida Sans Unicode";
}
.addP {
   float: left;
   min-width: 50%;
   font-weight:bold;
   font-size:40px;
   outline:1px solid red;
}
.wrap {
   position:relative; /*for AP img*/
   padding-right:50px; /*for AP img*/
   margin:10px;
   outline:1px solid red;
}
.heading,.heading.date,
.textArea1,.DateSpan0 {
   display:inline-block;
   vertical-align:top;
}
.heading,.heading.date {
   min-width:5em;
   margin-right:.25em;
   background:#fff;
}
div input[type=text],
div span {
   display:inline-block;
   vertical-align:middle;
}
.DateSpan input {margin-right:10px;}

input[type=text] {
   border-radius: 30px;
   background-color: rgb(128, 128, 137);
   border-style: none;
   padding: 15px;
   outline: none;
   margin-bottom: 10px;
}
img#plus {
   position:absolute;
   top:10px; right:10px;
   width:30px;
   height:30px;
   background:red;
   font-size:16px;
}

</style>

</head>

<body>

<div class="addP">
   <div class="wrap">
      <div class="heading">Location:</div>
      <div class="textArea1">
         <input type="text" name="Loc1">
         <br>
         <input type="text" name="Loc">
         <br>
         <input type="text" name="Loc">
         <img id="plus" src="plus.png" height="30" width="30" alt="img">
      </div>
   </div>
   <div class="wrap">
      <div class="heading date">Date:</div>
      <div class="DateSpan0">
         <span class="DateSpan"><input type="text" name="Date">in</span>
         <br>
         <span class="DateSpan"><input type="text" name="Date">in</span>
         <br>
         <span class="DateSpan"><input type="text" name="Date">in</span>
      </div>
   </div>
</div>


<script>
    $(document).ready(function() {
      var appendHere = document.querySelector("DateSpan0");
      var spanCounter = 1;

      $("#plus").click(function() {
        $("#plus").before("<br><input type='text' name='Loc'>");
        var newSpan = "<br><span class='DateSpan" + spanCounter + "'><input type='text' name='Date'>in</span>";
        appendHere.insertAdjacentHTML('beforeend', newSpan);
        var newestSpan = "DateSpan" + spanCounter;
        appendHere = document.querySelector(newestSpan);
        spanCounter++;
      });
    });

</script>

</body>
</html>

#3

Yes that is the crux of the problem as the browser will struggle to work out where those elements should appear when dynamically injected. It is not a viable structure in any sense.

I would suggest actually using a button element to add the fields as an image is not semantic and no help to screen readers etc. You can of course put an image in your button as a background or indeed an image.

You seem to be duplicating the 'name' attributes of the inputs so how will you distinguish fields they are when posted to the backend?


#4

Here's an example with nicer structured html and using a button element. I also utilised jQuery a little more as you were already using it to make life easier.

Most of it utilised Rays code but I simplified it a bit :slight_smile:

The name attributes of the inputs increment so that they can be accessed exactly but if you are building arrays you can just remove the counter.


#5

The JavaScript creates unique ids for each span it generates. Hence the use of the "spanCounter" variable to append on to each new span's id. Sorry if it was hard to tell through my messy JS :stuck_out_tongue: Looking back at my code, maybe I didn't implement it into the "Location" section, though, and I only did to the Date spans. The Date spans are definitely getting unique ids, and if the Location spans are not then they would definitely have in the future. That's probably where the confusion came from!

I was using spans in that way because I wanted the words "Location:" and "Date:" to show up right next to the inputs, and I had never previously seen anyone use CSS with divs to inline it like you did. I think using your CSS like that might solve my problems when I throw in some extra divs like you did!

How about I get the best of both worlds and use input with type=image? Is that still correct semantically?

Also, @PaulOB, I tried your cleaned up code but I didn't copy the CSS (because I didn't realize it had an effect on how things aligned) so I was having trouble getting the words "Location:" and "Date:" be on the same line as their inputs. Now I realize the CSS is an important part of that.

I fiddled with it for a while but have to leave now so I'll give an update tomorrow (fingers crossed) on if the implementation goes fine. Thanks!


#6

That's ok but a button is still better in this case and more easily stylable. As I said you can stuill use an image inside the button or as a background.

Yes I revised and simplified all the css and made it more semantic and easier to manage. You can see from the codepen that it works fine :slight_smile:


#7

@PaulOB @Ray.H External factors forced me to put my personal projects on hiatus for a couple of months, but I was finally able to just get back to it and implement your nested inline-block divs solution and it worked beautifully! Thanks so much for all the help, this was a huge benefit! I really appreciate everything!


#8

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.