Jump to content

Need CSS help (center DIV on page and wrap content around it)

KuJoe

So I have an idea I'm trying to figure out and I'm not even sure what terms to search for. Basically I want to have 2 DIVs on the page, one the full size of the page and another smaller DIV in the direct center of that DIV. To make it easier to follow DIV1 is the fullsized DIV and DIV2 is the smaller DIV. DIV2 will have a form in it and DIV1 will have content that will be populated via AJAX but as the content is added to DIV1 I want it to wrap around DIV2 so that the content doesn't disappear behind the DIV or cover it up. Any ideas how I can go about doing this or what I should be searching for on the almighty Google? Thanks!

-KuJoe

Link to comment
Share on other sites

Link to post
Share on other sites

I went a bit overboard on this answer, so...

 

TL;DR: I think this happens to be a perfect use case for CSS grid. CSS Tricks has great articles going in to depth on CSS grid, including the complete guide to CSS grid. Another great guide (which I found through CSS tricks) is Using CSS Grid the right way.  The situation you're describing is possible without div. Let's be honest, div is terrible and we should avoid it whenever possible. HTML 5 is all about semantics and providing meaning to the markup, and div has no meaning. Div should only be used when there is no semantically correct tag. I have a working CodePen demo that uses grid to accomplish what you're describing. Below is my explanation of how it works.

 

The Problem

 

As I understand the problem, we have what amounts to two distinct sections of a page. There is the body, and the form. The form exists as a child of the body, and the form is statically placed so that it remains in the center of the page. The form should never move from the center, nor should any other content from the body over run the form. The picture below is the mock up I have of this idea. The blue border is a hard border; i.e., content does not go beyond that border in either direction. The entirety of the white space is free to be filled with content from the form.

549225966_Artboard1ScaledDown.png.7e254b7c496efce087c0bde6a7b2ff42.png

The Solution Part 1: The HTML

 

We need to come up with valid HTML that describes this situation without using div. This just requires creating the markup for the form. There is light structure to this form. For a good guide on structuring HTML forms, see the MDN guide to structuring HTML forms. We're just gonna include inputs with placeholders and the submission button. I explicitly chose submit over the button input type and the button tag because with submit the user can press their keyboard to submit the form. The onsubmit attribute calls a populateBody() (more on that later) function and then follows that up with a return false to prevent the page from reloading.

<body>
    <form onsubmit="populateBody();return false;">
        <h2>Test Form</h2>

        <input type="text" name="username" placeholder="Username"><br>
        <input type="password" name="password" placeholder="Password"><br>

        <input type="submit" value="Submit">
    </form>
</body>

 

The Solution Part 2: The CSS (...or, the important part)

Solution Harder

 

This is the actual hard part of the problem, figuring out horizontal and vertical center alignment. Historically speaking, this has been difficult in CSS without resorting to pixel-perfect offsets and "position: absolute". IIRC, it was possible, just incredibly difficult and not really worth the effort. The introduction of flexbox to the CSS3 standard eliminates most difficulties with centering in one-dimension, and grid practically trivializes the problem of alignment in two-dimensions. Of course, that's assuming you can understand grid. I might be an idiot but I barely understand what I'm doing half the time with it. YMMV.

 

So, here's how it works as I understand it. When we display grid on a valid element, we render the element as a "checkerboard". The children of this element will exist in one or more of the spaces we've defined in the grid. For example, we can have a container grid that has four columns and five rows, making a total of twenty partitions of the container. There might be a paragraph that fits in one partition, e.g. a paragraph element at column 4, row 5. (That's the bottom right of the container). However, there might be an ad that fills up column 1, rows 1-5. So that the entire leftmost column of the container contains an ad.

 

For our purpose, we will treat the body as a grid with three columns and three rows. So, in the CSS, we set the width and height of the body to the width and height of the viewport respectively. We then define the columns and rows by their size relative to the body. The first column is 25% the width of the body tag, the second 50%, etc. Swap width for height and it's the same for the rows. Justify-content will center the content of each partition along the x-axis, and align-items will center the content of each partition along the y-axis.

body {
    width: 100vw;
    height: 100vh;
    display: grid;
    
    grid-template-columns: 25% 50% 25%;
    grid-template-rows: 25% 50% 25%;

    justify-content: center;
    align-items: center;
}

The CSS for the form is relatively straightforward. I set the width to 100% to fill its container, and center the items with text-align. The grid-column-start, grid-row-start, etc. tells the browser where to place the form relative to its parent's grid. In this case, I want it so that the form is in the second column and the second row, right in the center of our 3x3 grid. This can be expressed more succinctly but I'm being verbose for clarity.

form {
    grid-column-start: 2;
    grid-column-end: 2;
    grid-row-start: 2;
    grid-row-end: 2;

    width: 100%;

    text-align: center;
}

The Solution Part 3: The JavaScript

Solution with a Vengeance

 

This part is pretty straightforward too. It is just the implementation of the populateBody() function that the onsubmit attribute calls in the HTML. Obviously, for everyone this function will be completely different. However, I decided to include it for completeness and for the sake of highlighting just how it works. To anybody coming across this in the future, you probably shouldn't model your JavaScript off mine. This is just a proof of concept. So, I get the current value from both input tags, construct an element with a response message, and then append that constructed element to the body. If, you wanted to use a div instead, simply replace body with the id for the div, e.g. "#divOne". But please don't use div. I'm pretty sure it's listed as a war crime under the Geneva convention.

function populateBody() {
    let name = document.querySelector("input[type='text']");
    let password = document.querySelector("input[type='password']");

    let responseElement = document.createElement("p");
    responseElement.innerText = "Your name is " + name.value + ", and your password is " + password.value;

    document.querySelector("body").appendChild(responseElement);
}

Solution Part 4: Concluding Comments

Live Free or Solution

 

Notice that if you run all this code together (or if you just look at the CodePen), you'll see that the paragraph elements are added in a weird way. That's because of how grid works. Each paragraph element is filling up a partition of the grid (except column 2, row 2). After column 3, row 3, new columns and rows are added as needed, although the spacing will be off. You can easily fix this by adding some CSS for the paragraph element by specifying what column and row it should be in. I presume the actual JavaScript will only fill up one grid. I hope this wasn't completely useless and that it's at the very least a good jumping off for your specific issue. I'm kinda invested in this now and wonder if there are different and / or better approaches to this.

Link to comment
Share on other sites

Link to post
Share on other sites

4 hours ago, WatermelonLesson said:

I went a bit overboard on this answer, so...

Thank you so much for taking the time to type all of that up, it was really informative and hopefully I'll be able to utilize it in the future but for my current project I don't think it will work because I would need to utilize more space (i.e. fill up one one row before moving to the next). I opted to just move the form to the top of the page and populate a DIV underneath it. If this was anything other than a personal project for my own use I would definitely look into doing it "the correct way" but for now I was able to use a lot of virtual duct tape to make things work enough.

 

This is the best I could come up with, just don't look at the source if you value your sanity (I refuse to give my <center> tag! ?): https://imgs.one/

-KuJoe

Link to comment
Share on other sites

Link to post
Share on other sites

5 hours ago, KuJoe said:

Thank you so much for taking the time to type all of that up, it was really informative and hopefully I'll be able to utilize it in the future but for my current project I don't think it will work because I would need to utilize more space (i.e. fill up one one row before moving to the next). I opted to just move the form to the top of the page and populate a DIV underneath it. If this was anything other than a personal project for my own use I would definitely look into doing it "the correct way" but for now I was able to use a lot of virtual duct tape to make things work enough.

 

This is the best I could come up with, just don't look at the source if you value your sanity (I refuse to give my <center> tag! ?): https://imgs.one/

 

Your solution isn't bad if it works! I just personally try to avoid div whenever possible. I modified my code so that it works closer to what you have on your website. It just boils down to an extra line of HTML and some CSS. I add

<span>Save this link to blah blah...</span>

before the form arbitrarily to fill up the first row of the grid. The CSS for the span just fills the span along the first row and I added some flavor to the paragraph elements so I can see how they're filling up the grid.

span {
  grid-row-start: 1;
  grid-row-end: 1;
  grid-column-start: 1;
  grid-column-end: 4;
}

p {
  background-color: #ddd;
  text-align: center;
}

The trick to filling up the specific rows is using the "nth-child" CSS selector along with some basic modular arithmetic. TBH, I figured it out through some good ol' trial-and-error; but, it works. The page doesn't look pretty but it works and feels pretty efficient.

p:nth-child(3n + 2) {
  grid-column-start: 1;
  grid-column-end: 2;
}

p:nth-child(3n) {
  grid-column-start: 2;
  grid-column-end: 3;
}

p:nth-child(3n + 1) {
  grid-column-start: 3;
  grid-column-end: 4;
}

 

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×