-1

I have an HTML structure with three structures of some element and two p's right under:

<some_tag></some_tag>
<p></p>
<p></p>

<some_tag></some_tag>
<p></p>
<p></p>

<some_tag></some_tag>
<p></p>
<p></p>

In practice I have much more than just three structures (more like thirty) so I need automation.

I need to select each last p in the first two structures, but not the last p in the last structure.

My problem

There seem to be no CSS way to do the selection I desire.

Considering an HTML way of wrapping each non-last, some_tag structure in some other element (like a div) I conclude I don't like this solution as it seems to me unaesthetic.

My question

Do you know a way to automate the described selection via JavaScript?

  • I'd like to this to easily design the aforementioned elements with CSS. –  Aug 21 '18 at 05:30
  • Is it possible to warp a `
    ` for each section?
    – Chaska Aug 21 '18 at 05:31
  • Will there always be more than one p following each heading? Your question is tagged [javascript], so would something like a loop be acceptable? – BoltClock Aug 21 '18 at 05:31
  • Yes, usually there will always be a `p`. My stance is that some loop will help. –  Aug 21 '18 at 05:33
  • You can style all the last `

    `s in every structure and then, target the very last `

    ` on the page and remove the styling.

    – Titus Aug 21 '18 at 05:33
  • so, you want to select the last p in a h2 or h3, but not a h4 - seems fairly simple given the example you've chosen to use – Jaromanda X Aug 21 '18 at 05:35
  • @Titus this seems promising, but I don't know how to remove the styling of the very last after styling all lasts, especially as it can have a dynamic `nth-child` number. –  Aug 21 '18 at 05:36
  • @JaromandaX it will not always be a `h4` or anything else --- it can be any given tag but I still need all last `p` besides the very last one. –  Aug 21 '18 at 05:37
  • simply put, you want to select any `

    ` who has a next sibling and that sibling isn't a `

    ` (there is nothing **last** about any of the `

    ` except for the one you **don't** wan't to select

    – Jaromanda X Aug 21 '18 at 05:47
  • @JaromandaX "structure" is metaphoric here --- there is no nesting. Last is also metaphoric here because indeed as you point out these `p` I'd like to select aren't last in the CSS meaning. –  Aug 21 '18 at 05:50
  • so it's any `

    ` that has a next sibling, and that sibling isn't a `

    ` - isn't that what you want? I don't think you can do this with CSS - because there's no way to refer to next sibling (or children for that matter) in a way that the target element isn't that sibling or child

    – Jaromanda X Aug 21 '18 at 05:52
  • @JaromandaX I think it's a good way to put it. –  Aug 21 '18 at 05:53
  • what I mean is, you have `a+b` but the CSS target is `b` - i.e. selects any `b` whose previous sibling is `a` ... but, there's no CSS syntax equivalent (as far as I know) that allows you to target `a` whose next sibling is `b` – Jaromanda X Aug 21 '18 at 05:55
  • you should wrap them in a container that's the proper way to define a html structure. If you add a wrapper class it would be more easier to sort it out' – Viira Aug 21 '18 at 06:01
  • the way your structure is, you would need a css previous sibling selector ... see https://stackoverflow.com/questions/1817792/is-there-a-previous-sibling-css-selector – Jaromanda X Aug 21 '18 at 06:08

4 Answers4

2

This is not a good HTML structure for what you want to do. It will be much easier if you wrap each set of hX and p inside a container tag like a div.

Otherwise you are going to have to loop over each element with JavaScript and decide whether to apply styles (if the current element is a p, and there is a next element, and it's not a p).

We Are All Monica
  • 13,000
  • 8
  • 46
  • 72
0

Is your layout created dynamically? You could always use css classes to handle this easily. If you are not able to control this with layout here is a quick way to do it:

#myLayout *:not(:last-child) > p:last-child {
  color: red
}

This code grabs every parent with a p child. It should ignore the last child sibling and always grab the last p. I would recommend replacing the * with a node or a css selector though to prevent unexpected results. I also recommend at least limiting possible issues by enclosing everything in a container like below.

<div id="myLayout">
  <div>
    <h2>h1</h2>
    <p>p1</p>
    <p>p2</p>
  </div>
  <div>
    <h2>h1</h2>
    <p>p1</p>
    <p>p2</p>
  </div>
  <div>
    <h2>h1</h2>
    <p>p1</p>
    <p>p2</p>
  </div>
</div>
pg316
  • 1,380
  • 1
  • 8
  • 7
0

You can do this with JavaScript, here is an example:

const elements = document.querySelectorAll("*");
let latestParagraph;
const paragraphsToStyle = [];

for(const element of elements){
  if(element.tagName === "P"){
    latestParagraph = element;
  }else{
    if(latestParagraph){
      paragraphsToStyle.push(latestParagraph);
    }
  }
}

paragraphsToStyle.pop();

for(const paragraph of paragraphsToStyle){
  paragraph.style.color = "red";
}
<h3>h</h2>
<p>p1</p>
<p>p2</p>
<h2>h</h2>
<p>p3</p>
<p>p4</p>
<h1>h</h2>
<p>p5</p>
<p>p6</p>

This will only work if there is no nesting.

The script runs through all the elements on the page and when a non paragraph element is encountered, it adds the latest paragraph found to the paragraphsToStyle array. At the end of the first loop, the last paragraph on the page is removed from the array paragraphsToStyle.pop()

Titus
  • 22,031
  • 1
  • 23
  • 33
-1

Edit: As others have mentioned, you may want to restructure your HTML so that it can work with selectors more easily. But if that's not possible, you can use JavaScript for this. In this case, all you have to do is see if the element is a 'p' tag and if the next element is not a 'p' tag:

var children = document.getElementById('content').children;
for (let i = 0; i < children.length - 1; i++) {
  let nextTagName = children[i+1].tagName;
  if (children[i].tagName === 'P' && nextTagName !=='P') {
      children[i].classList.add('selected');
  }
}
.selected {
  color: aqua;
}
<div id="content">
    <h2>Heading 1</h2>
    <p>p 1</p>
    <p>p 2</p>
    <h3>Heading 2</h3>
    <p>p 3</p>
    <p>p 4</p>
    <h4>Heading 3</h4>
    <p>p 5</p>
    <p>p 6</p>
</div>
Steve
  • 10,435
  • 15
  • 21