1

I wrote a small site that queries a MongoDB instance containing prior brute-force attempts by IP to help with firewall management. Originally written with a table layout, I rewrote the site to use a grid layout. The page layout and grid CSS are as follows:

enter image description here

The grid-template uses alternative named areas:

/* using alternative named grid areas */
.gridlayout {
  display: grid;
  grid-template-columns: auto auto;
  grid-template-rows: 50px auto auto 50px;
  gap: 4px;
  grid-template-areas:
    "header header"
    "left right"
    "data data"
    "footer footer";
}

header {
  grid-area: header;
  /* padding: 15px 15px 10px 15px; */
}

left {
  grid-area: left;
  /* overflow-y: scroll; */
  min-height: 0;
  min-width: 0;
}

right {
  grid-area: right;
  min-height: 0;
  min-width: 0;
}

data {
  grid-area: data;
}

footer {
  grid-area: footer;
  margin-top: 10px;
}

header, footer {
  background-color: #22243E;
  /* text-align: center; */
}

The page-controls are in the left grid area and the grid area also shows/hides divs with the HTML forms, snippets of information like site config (path variables/content), a dump of the PHP PRG $_SESSION['xxx'] values, and database connection status, etc.. The right grid area contains up to the 10 most recent database queries. The data section shows any response database records in table format. This all worked well without any recalculation of the grid, showing/hiding information in the left grid area and updating the values in the right grid area and data area as needed.

For example, a quick screenshot of the page is:

enter image description here

Showing the Database status simply expands within the left grid area (as do all of the other divs controlled by the buttons shown):

enter image description here

The "Config", "PRG", and "Database" buttons all show/hide divs in that left grid area and none have ever caused reflow until the "CIDR" button was added to include another 3-input form that uses the same area as the Quick Query and full Query forms do (they are all mutually exclusive and only 1 form is actually shown in the page at any one time) That all works perfectly fine.

The page source and div layout is:

<?php
declare(strict_types=1);    /* require strict type declarations */

/* set pageTitle */
$pageTitle = 'journal COMM of BadActors';

/* require ./include/site.php which has php preamble for each page */
require_once __DIR__ . '/include/site.php';

/* PRG must be before header
 * handle POST submission and confirmation
 */
include './include/site-PRG.php';

/* include page header info */
include 'header.php';

?>

<div class="gridlayout">

  <header>  <!-- grid header div -->
    <div id = 'header'>
      <p id = 'hdrtext' class = 'hftext'>Journal Bad-Actors - in Grid</p>
    </div>
  </header>  <!-- grid header div close -->

  <left>  <!-- grid left div -->
    <div style=''>
      <div class = 'container' style = 'margin-left: 15px'>
        <p class = 'mp0'>
          <span style='font-size: 110%; font-style: italic;'>
            <b>Prior Brute-force Attempts</b>
          </span><br>
          <i>Network Security Class is in...</i><br>
          <hr>
          <button type='button' onclick='toggledisp("showconfig")'>Config</button>
          <button type='button' onclick='toggledisp("showprg")'>PRG</button>
          <div id = 'showconfig' class = 'container'  style='display: none;'>
            <?php $config->showcfg(); ?>
            <b>incldir():</b> <?php echo $config->get_siteincl(); ?> <br>
            <b>stylesheet:</b> <?php echo $config->get_sitecss() . '/site.css'; ?> <br>
          </div>
          <div id = 'showprg' class = 'container'  style='display: none;'>
            <?php showprg(); ?>
          </div>
        </p>
        <p class = 'mp0'>
          <hr>
          <button type='button' onclick='toggledisp("dbmongo")'>Database</button>
          <button type='button' onclick='toggledisp("qweryresults")'>Records</button>
          <button type='button' onclick='querydisp()'>Query</button>
          <!-- <button type='button' onclick='toggledisp("frmcidr")'>IP/CIDR</button>
          <button type='button'
                  onclick="window.location='https://2pi.3111skyline.com/tmp/db/cidr/';">
                    IP/CIDR
          </button> -->
          <button type='button' onclick='cidrdisp()'>IP/CIDR</button>
          <!-- <button type='button' onclick='toggledisp("frmipqwry")'>Query</button> -->
          <!-- for query result count, just use DOM table.rows.length - 1 instead of
              converting from the mongo PHP cursor object, must simpler -->
          <div id = 'qrcount' style = 'float: right; background: #32313B; font-size: 10pt; padding: 5px; margin-top: 3px;'></div>
          <div id = 'nstfrmblk' style = 'overflow: scroll; min-height: 0; min-width: 0;'>
            <div id = 'qdiv' style='display: block;'>
              <?php include './include/frm-query-rhost-ruser.php'; ?>
              <?php include './include/frm-query-quick-rhost.php'; ?>
            </div>
            <!-- <div id = 'cdiv' style='display: none; overflow: scroll;'> -->
            <?php include './include/frm-cidr.php'; ?>
            <!-- </div> -->
          </div>
          <div id = 'dbmongo' class = 'container'  style='display: none;'>
            <?php
              $dbobj->get_db_status();
              if (isset ($_SESSION['insstr'])) {
                printf ("document: %s<br>", $_SESSION['insstr']);
                unset ($_SESSION['insstr']);
              }
            ?>
          </div>
        </p>
        <!-- <p class = 'mp0'> -->
          <?php
            /* output any errors thrown */
            if ($dmsg->msg_count() > 0) {
              echo "<p class = 'mp0'>errors: " . $dmsg->err_count() . ", warnings: " . $dmsg->warn_count() . ", messages: " . $dmsg->info_count() . "<br>";
              $dmsg->errmsg (7);
              echo "</p>";
            }
          ?>
        <!-- </p> -->
      </div>
    </div>
  </left>  <!-- grid left div close -->

  <right class='container' style='margin-right: 20px;'>  <!-- grid right div -->
    <!-- query history displays last 10 DB queries -->
    <div id = 'qhistdiv'>
      <i><b>
      Query History List
      </b></i>
      <div id='qryhist' class='container' style='overflow-y: scroll;'></div>
    </div>
    <!-- CIDR/IP range result display (toggles qhistdiv display: 'none') -->
    <div id = 'cidrdiv' style = 'display: none;'>
      <div id = 'rttitle' style='font-weight: bold; font-style: italic;'></div>
      <div id = 'cidrres' class = 'container'>
        <div id = 'cidrdesc' style='background: #1D1E23; font-weight: bold; margin-bottom: 3px; padding: 5px 0 5px 5px;'></div>
        <div id = 'cidrdata' style='padding-left: 15px;'></div>
      </div>
    </div>
  </right>  <!-- grid right div close -->

  <data id = 'qweryresults'
        class = 'container'
        style = 'margin: 10px 20px 0 15px; display: none;'>
        <!-- grid data div -->
    <div id = 'qresultstable'>
      <?php
        if (isset ($_SESSION['queryready'])) {
          $dbobj->db_query_fmt ($_SESSION['qobj'], 'fmt_journal_id');
          // unset ($_SESSION['queryready']);
        }
        else {
          /* just output table headings so nrows is 0 below and Query Results is 0 */
          printf ("<div class = 'container'><table id='queryres' class='rowalt' style='width: 80%%; margin: 0 auto;'><caption style='font-size: 110%%; margin-bottom: 10px;'><b>Badactors - rhost, ruser<b></caption><tr style='background-color: #32313B; font-weight: bold;'><th style='width: 25%%; padding: 5px 0 5px 5px;'>timestamp</th><th style='width: 25%%; padding: 5px 0 5px 5px;'>rhost - IP</th><th>ruser - Username</th></tr></table></div>");
        }
      ?>
    </div>
  </data> <!-- grid data div close -->

  <footer>  <!-- grid footer div -->
    <!-- include page footer -->
    <?php include 'footer.php'; ?>
  </footer>  <!-- grid footer div close -->

</div>  <!-- gridlayout close -->

All of the various divs caused no problem causing the page to recalculate/reflow until I included another form to allow CIDR/IP Range calculations to be done on the same page (I was forever having to do that for whois data that didn't provide a CIDR). Adding this additional form, even if it remains hidden and unused causes the entire grid to be redrawn when a query is submitted.

This redrawing occurs even if the only additional information in the <div> is a single line of text, as short and simple as "Boo!". For what it is worth, here is the additional form I attempt to include with <?php include './include/frm-cidr.php'; ?> (and note the commented "Boo!" which can be the only text in the <div> and reflow still occurs):

<div id='frmcidr' class='frmtext' style='display: none;'>
  <!-- <p><b>Boo!</b></p> -->
  <form id='frmcidr01'
        class='frmtext'
        action='<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>'
        method='post'>
    <p class='frmhdg'>IP Range/CIDR Conversion</p>
    <div class="frmcontainer">
      <table style='width: 100%;'>
        <tr>
          <td style='width: 15%;'>
            <label for='ipstart'>Start IP</label>
          </td><td>
            <input  type='text'
                    id='ipstart'
                    name='ipstart'
                    placeholder = 'Enter Beginning IP Address'>
          </td>
        </tr><tr>
          <td>
            <label for='ipend'>End IP</label>
          </td><td>
            <input  type='text'
                    id='ipend'
                    name='ipend'
                    placeholder='Enter Ending IP Address'>
          </td>
        </tr><tr>
          <td>&nbsp;</td>
          <td style='padding-top: 15px;'>
            <button id='btnip01' type='submit' class='btntext' name='btnip01' value='true'>CIDR</button>
          </td>
        </tr>
      </table>
      <!-- <hr style="width: 80%;"> -->
      <table style='width: 100%; padding-top: 10px;'>
        <tr>
          <td style='width: 15%;'>
            <label for='cidrentry'>CIDR</label>
          </td><td>
            <input  type='text'
                    id='cidrentry'
                    name='cidrentry'
                    placeholder = 'Enter CIDR'>
          </td>
        </tr><tr>
          <td>&nbsp;</td>
          <td style='padding-top: 15px;'>
            <button id='btncidr01' type='submit' class='btntext' name='btncidr01' value='true'>IP Range</button>
          </td>
        </tr>
      </table>
    </div>
    <p style='margin: 0; padding: 0;'>&nbsp;</p>
  </form>
</div>

However, also note, that removing this div, not matter whether it just contains "Boo!" or the full form -- no reflow of the grid/page occurs and only the individual data values in the tables are updated as they should be. So it is the inclusion of this one line <?php include './include/frm-cidr.php'; ?> that causes the reflows to start on the next normal "quick query" (or any other) form submission. Remove that included div/form and all is well.

I've been though the suggestions of ensuring .position isn't left as default so that min-height/min-width can be set as the suggested work-around, I've set the values large enough to encapsulate the largest item in the left area and also tried at 0. Other than changing the original size of the left/right grid areas, it has no effect on preventing the page reflow. I've been though the grid documentation on MDN and W3schools and about every "prevent reflow" article I can find, but nothing makes much sense.

I don't do a lot of web development, mostly just for tools for personal use, so I'm not 100% sure I understand all the reasons that a reflow will be triggered other than a size issue the rendering engine thinks it needs to redraw everything for.

There are no errors or warning shown on page inspection, so it isn't a syntax or JS or header or CSS issue. It literally seems like I've hit a "one-div-too-many" threshold by adding the additional form (even if it just contains the one-line "Boo!")

I apologize for the question length, but wanted to include as close to a Minimum Reproducible Example as possible (the site isn't public, so there is no way to provide the full site) What I can't understand is why, if I commented out everything in the div that is include except the text Boo! -- why that makes a difference on causing reflow when a query is submitted -- even if that newly added div remains hidden? That is a much smaller inclusion than any of the other divs in the left grid area that do not cause any reflow.

What else do I need to check or provide to help figure out why this tiny addition cause full grid reflow when any of the existing forms are submitted?

The following is the generated HTML (it's a bit rough, but not that much) and I'll include the site CSS file afterwards (the full grid.css is already posted above). I have to link the files, as they make the character limit exceed the 30000 allowed (but not by too much).

Full Generated HTML

journal-grid-generated html (link valid until Sept. 9, 2025)

Full site.css

site.css (link valid until Sept. 9, 2025)

Full site.js

site.js (link valid until Sept. 13, 2025)

8
  • I'm not sure if you are using some kind of web components or so, but if this is meant to be plain HTML, the first thing I would do is change the elements "left" and "right" to divs and use "left" and "right" as classnames. In your CSS code the selectors would then be ".left" and ".right" Commented Jun 7 at 18:09
  • Thanks for the reply, and this is only straight css/js/html. I don't use anything else (other than PHP for server side). The left/right naming is just a convenient Grid template areas alternative for naming grid areas. I'll try again reworking them as div and css classes, but it just seems something else is taking place. The puzzling part is adding a div containing only static text like "Boo" (or whatever) is all that it needed to cause the page to redraw on form update. That is the puzzler. Commented Jun 9 at 1:39
  • 1
    It would be great if you could add the HTML code that gets generated. So without all the php code. And your CSS code as well Commented Jun 9 at 18:01
  • Thank you obs. I've added a link to the full generated source and the site.css file. (the full grid.css file is already posted). I tried including them in the question, but the generated html is about 500 lines and then css about 200 lines so it exceeded the 30,000 character limit. Let me know if you need to see anything else. The site isn't reachable publicly, so other than the DB credentials, there isn't anything sensitive. PHP doesn't disclose the credentials anyway. The rest is just IP info on bad-actors trying to crack my public server. Commented Jun 11 at 2:24
  • In your second code snippet, with "Boo" commented out, the whole form is set to display: none, which makes it pointless to use or include here--was that intentional? Can you please modify it so that it accurately reflect how it is being used/_shown_ to the user (I assume just by removing that style or adding a style to a child to reset display back to block or grid that you just forgot to include)? Commented Jun 11 at 13:23

1 Answer 1

0

enter image description hereTo fix this issue

  1. Convert <left>, <data>, <right> tags → <div class="left">, etc.

  2. Update CSS grid-template-areas to use .left, .right, .data.

  3. Confirm hidden form has plain display: none; with no competing styles.

test.html

grid.css

Sign up to request clarification or add additional context in comments.

7 Comments

Thanks Imran. I've changed all grid css to , e.g. .left { grid-area: left; } and then implemented the changes as <div class='left'> and confirmed the exclusive forms simply use display: none; and there are no competing (differing) display: setting for any of the forms. (of course when the forms are swapped they are made visible with display: block;, while the one shown is hidden with display: none;). Unfortunately, making the changes made no difference whatsoever in the operation of the page or the page reflow when a query was submitted. Any other thoughts?
Since the issue still persists, my guess is that the reflow might be triggered by something else, maybe a JavaScript operation that's manipulating DOM elements or triggering a redraw. Could also be caused by a layout shift due to dynamic content injection or container resizing.
I think you assessment is 100% correct. What I was trying to identify and understand through the question is "Why?". I have the equivalent setup that simply omits the <div id='frmcidr' ...> but in all other respects is exactly the same, including showing and hiding the two variants of the MongoDB query form. Since the cidr form is slightly longer than the full MongoDB query form, I've even tried making the cidr form the default so the page computes the largest of the 3 forms that get swapped in/out -- no change. It has left me scratching my head.
To make the above clear, the only difference between the 2 versions of the site is the addition of the <div id='frmcidr' ...> form. Without it, the page never reflows and all values a properly updated in-place without any page redrraw except the updated fields. As soon as I include the additional form (even if it just includes a single 3-characters of text), the entire page reflows/redraws every time a query is submitted -- even if the added div is not displayed (hidden). That is the bewildering part. Anything I can do at the left/right grid css level to test?
It’s definitely strange that the hidden <div> is still causing a reflow. At the CSS level, you could try setting position: absolute; visibility: hidden; height: 0; overflow: hidden; on #frmcidr to fully remove its layout impact. That might help isolate whether it’s being considered during render.
Chuckling... Your not going to believe this, because I don't believe this, but setting <div id='frmcidr' class='frmtext' style='position: absolute; visibility: hidden; height: 0; overflow: hidden;'> -- it still reflows. Glad there is no cliff around here, I might just jump :). Thank you for all your help and suggestions. At this point, I think just start again with the base site that has no problems and rewrite the implementation of the 3rd form. There has to be something goofy somewhere. I'll report back if I turn anything up in the server-side logic.
Haha..honestly, I do believe it .. sounds like a smart plan. let me know if the server side turns up anything interesting.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.