3

I have the next scenario

<blockquote>
    <p>text text text</p>
    <p>text text text</p>
    <p><cite>author cite</cite></p>
</blockquote>

I am trying to select just the p elements that are inside of blockquote but not contain child cite elements to add a " before and after every p element

my approach is

blockquote p:not(:has(> cite))::before,
blockquote p:not(:has(> cite))::after
{
  content: '"';
}

but it is not working as it still has no support yet, anyone can give me a hand? Thank you in advance

EDIT:
I want to point, It is not possible to modify the HTML by adding some class to p elements because the HTML is provided from a remote server.

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
Raikish
  • 634
  • 2
  • 6
  • 20
  • i think is impossible, why don't use js? – Simone Rossaini Dec 18 '20 at 11:50
  • If its from a remote server , you should be probably using an iframe . And You can not change the styles of the page that resides within the iframe. Or are you doing a webscrap in your server of other websites and forwarding to your your site by appending some stylesheets ? – Sandrin Joy Dec 18 '20 at 13:26
  • @sandrin joy The server parses a txt file and extracts the data, then it converts to HTML and it stores to a DB and after that is provided to the client app through API that resides in a server. I don't need an iframe, I have access to the HTML code in the client but it shouldn't be modified, anyway, this is not the scope of the question. – Raikish Dec 18 '20 at 13:44
  • "I have access to the HTML code in the client but it shouldn't be modified" - but isn't this (changing css) a part of modifying html. ? – Sandrin Joy Dec 18 '20 at 14:01
  • @SandrinJoy Maybe I am wrong but IMO, modify the CSS it is not understood as modify the HTML – Raikish Dec 18 '20 at 14:50

4 Answers4

3

I have given two solutions for jquery and javascript. These decisions have the same principle.

In this code, the parent <p> is accessed from the assigned tag <cite>, with the subsequent assignment of class no-content with the missing content: parameter:

.no-content:before,
.no-content:after {
  content: none;
}

Default html structure.

  • jquery solution:

$('cite').closest('p').addClass('no-content');
blockquote p::before,
blockquote p::after
{
  content: '"';
}

.no-content:before,
.no-content:after {
  content: none;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<blockquote>
    <p>text text text</p>
    <p>text text text</p>
    <p><cite>author cite</cite></p>
</blockquote>
  • javascript solution:

document.querySelector('cite').closest('p').classList.add('no-content');
blockquote p::before,
blockquote p::after
{
  content: '"';
}

.no-content:before,
.no-content:after {
  content: none;
}
<blockquote>
    <p>text text text</p>
    <p>text text text</p>
    <p><cite>author cite</cite></p>
</blockquote>
s.kuznetsov
  • 14,870
  • 3
  • 10
  • 25
  • 1
    As this question is about CSS I can not mark it as the correct solution, but it is a very good solution using javascript. – Raikish Dec 18 '20 at 14:55
  • @Raikish, Thanks for your feedback. But you will not solve your problem correctly without css. If there is a solution for css, then this solution will be a "crutch". If you want the right solution, then use the javascript solution. – s.kuznetsov Dec 18 '20 at 15:13
3

A hacky idea to hide the content with the cite element

blockquote p::before,
blockquote p::after {
  content: '"';
}

blockquote p cite {
  background: #fff; /* this need to match the main background */
  margin: 0 -6px; /* a trial and error value, you need to adjust it based on your font*/
  display: inline-block;
  position: relative;
}
<blockquote>
  <p>text text text</p>
  <p>text text text</p>
  <p><cite>author cite</cite></p>
</blockquote>
Temani Afif
  • 245,468
  • 26
  • 309
  • 415
0

There are multiple ways you can achieve that. You can add CSS selectors, such as classes to the p tags you want to surround with the content.

HTML:

<blockquote>
  <p class="quote">text text text</p>
  <p class="quote">text text text</p>
  <p><cite>author cite</cite></p>
</blockquote>

CSS:

.quote::after,
.quote::before {
  content: '"';
}

or if you prefer just using elements as selectors, you can select the last p to remove it's quote:

CSS:

blockquote p::last-child:after,
blockquote p::last-child:before {
  content: none;
}

Or with the same result:

blockquote p span::before,
blockquote p span::after
{
  content: '"';
}
Mario Petrovic
  • 7,500
  • 14
  • 42
  • 62
Etsh
  • 116
  • 2
  • 11
  • I can not modify the HTML because it is provided from some server, also in some situations the `cite` is not in the last `p` of the `blockquote` – Raikish Dec 18 '20 at 12:33
  • Can you use javascript? Then some of us might be able to come with a solution in javscript. Look at sergey kuznetsov's response for example. – TimonNetherlands Dec 18 '20 at 12:45
  • I did some digging and on MDN and CSS selectors and I found nothing that could help you. I am sorry :/. The closest I got was a selector called [:has](https://developer.mozilla.org/en-US/docs/Web/CSS/:has), but sadly it doesn't work but you can have a look. – Etsh Dec 18 '20 at 13:19
0

The closest option CSS offers is blockquote p *:not(cite). The problem is that the wildcar selector * selects anything but text nodes, so it doesn't help.

Unfortunately, the :empty select does exactly that, as in it does lookup text nodes so blockquote p:empty also won't work since it doesn't consider any of the p elements to lack children.

Luckily, a new selector is scheduled to appear, namely :has which will allow to perform selections like blockquote p:not(:has > cite). We're not there yet so until then adding a span to your p elements may be a solution:

  <blockquote>
    <p><span>text text text<span></p>
    <p><span>text text text</span></p>
    <p><cite>author cite</cite></p>
  </blockquote>

In CSS:

blockquote p *:not(cite)::before,
blockquote p *:not(cite)::after
{
  content: '"';
}

Or with the same result:

blockquote p span::before,
blockquote p span::after
{
  content: '"';
}
TimonNetherlands
  • 1,033
  • 1
  • 6
  • 6