Alexis Wilke
Alexis Wilke

Reputation: 20818

Is it possible to place a DIV between two paragraphs using CSS only?

I think I cannot do that one in CSS, but wanted to see whether someone would have such a solution...

I have a div with the page content, a div which can be in several different location in the HTML, and a set of paragraphs. The CSS would have to place the second div between two paragraphs.

There is a sample HTML:

<div id="to-be-placed">Move Me</div>
<div id="content">
  <p>P1</p>
  <p>P2</p>
  <p>P3</p>
  <p>P4</p>
  <p>P5</p>
</div>

Say we want to place the "#to-be-placed" div after the 3rd paragraph, is there a way to do that in CSS? I can reference the 3rd paragraph as so:

content.p:nth-child(3)

But I really don't see a way to tell CSS to move my DIV to that location...

Note: the #to-be-placed div could be inside the #content div, at the beginning or at the end.

P.S. Please, don't come up with hard coded sizes and positions. That won't work.

P.S. Just in case you get all excited about jQuery. I know how to do it with jQuery. So no, I don't need you to give me such an answer. (see How to add div tag in-between two paragraphs when wrapped inside main div using jquery for those who wonder.)

Upvotes: 2

Views: 820

Answers (4)

Zach Saucier
Zach Saucier

Reputation: 26014

For those who stumble upon this answer (like me) who don't mind using JavaScript:

I wanted to allow users to add content between paragraphs. So for my use case I only cared about nearby paragraph tags above or below a click.

As such, I used this code:

const MAX_TRIES_PER_DIR = 10;
const PX_SHIFT_EACH_TRY = 2;

function findClosestPToClick(e) {
  const above_res = checkNearbyPosForP(e.pageX, e.pageY, -PX_SHIFT_EACH_TRY, MAX_TRIES_PER_DIR);
  const above_dist = above_res ? Math.abs(e.pageY - above_res.y) : Infinity;
  const below_res = checkNearbyPosForP(e.pageX, e.pageY, PX_SHIFT_EACH_TRY, MAX_TRIES_PER_DIR);
  const below_dist = below_res ? Math.abs(e.pageY - below_res.y) : Infinity;
  
  if (above_dist <= below_dist) {
    if (above_dist === 0) {
      const el_height = above_res.el.offsetHeight;
      if (Math.sign(e.offsetY - el_height / 2) < 0) {
        return {
          el: above_res?.el,
          place_before: true,
        }
      }
      return {
        el: above_res?.el,
        place_before: false,
      }
    }
    return {
      el: above_res?.el,
      place_before: false,
    }
  } 
  return {
    el: above_res?.el,
    place_before: true,
  };
}

function checkNearbyPosForP(x, y, shift, num_tries) {
  const p = document.elementFromPoint(x, y)?.closest('p');
  if (p) return { el: p, y };
  if (num_tries > 1) {
    return checkNearbyPosForP(x, y + shift, shift, --num_tries);
  }
  return;
}

document.addEventListener('click', function(e) {
  const res = findClosestPToClick(e);
  if (res.el) {
    return console.log(res.el.innerText, res.place_before);
  }
  console.log('No p found near click');
});

Demo

Upvotes: 0

Subash
Subash

Reputation: 7266

Short answer: No you cannot do that. CSS (Cascading Style Sheet) is designed for styling. It is not designed to be used to manipulate DOM elements. JavaScript on the other hand is built for doing that. So if you happen to be wanting to use CSS for manipulating your DOM then you might want to re-think your approach to the solution.

Upvotes: 2

JenGettings
JenGettings

Reputation: 41

You can't do that exactly, but a possible workaround would be to define the div as the ::after element on the 3rd p element. This technically puts the div inside the p, but it might do what you're looking for.

p:nth-child(3)::after {
    content: "Move Me";
    display: block;
}

Here's a fiddle: https://jsfiddle.net/me5su05f/1/

Upvotes: 2

Maximillian Laumeister
Maximillian Laumeister

Reputation: 20399

This cannot be done using CSS, as CSS does not provide any mechanism for moving elements in HTML, only for styling existing elements and adding new content through the use of pseudoelements. The best you're going to get is a solution that uses JavaScript or jQuery.


If you only want to add styled text content, you can add that using the ::after pseudo-element in CSS, but it does not support HTML, only plain text:

p:nth-child(2)::after {
    content: "- Added content";
}
<div id="content">
  <p>P1</p>
  <p>P2</p>
  <p>P3</p>
  <p>P4</p>
  <p>P5</p>
</div>

Upvotes: 2

Related Questions