Can CSS psuedo content pull the element's text? - css

<p class="test">Lorem Ipsum Dolor.</p>
Can a CSS psuedo-element's (:before/:after) content property pull from the DOM element's plain text?
.test:after{ content: html; }
With the result of...
Lorem Ipsum Dolor.Lorem Ipsum Dolor.
Looking for a non-JavaScript solution (if one is possible).
Thanks :)

No, it's currently not possible to retrieve the element's text and display it using the content property without using JavaScript. However, as I pointed out in the comments, you can use the CSS attr() function in order to retrieve the element's attribute value and display it.
For instance, you could add a custom data-content attribute to the element:
[data-content]:after {
content: attr(data-content);
}
<p data-content="Lorem Ipsum Dolor."></p>
If you want to display the same string twice (as your question implies), you could simply use multiple attr() functions:
[data-content]:after {
content: attr(data-content) ' ' attr(data-content);
}
<p data-content="Lorem Ipsum Dolor."></p>
If you use JavaScript, you could simply iterate over the elements and add a custom data-content attribute to the element(s) based on the textContent property of the element:
[].forEach.call(document.querySelectorAll('[data-content]'), function (element) {
element.dataset.content = element.textContent;
});
[data-content]:after {
content: ' ' attr(data-content);
}
<p data-content>Lorem Ipsum Dolor.</p>
<p data-content>Some other string.</p>
It's also worth mentioning that the content property's value is still rendered as a string (and not HTML).

Related

Target elements without *any* attributes?

Is there a selector method that allows policing whether, eg. the HTML tag is a clean "<html>" with no attributes whatsoever?
I'm trying to create a Stylish override sheet for browser-generated image pages in Firefox, but I essentially have to apply it to all URIs since such pages are always still ostensibly from the images' own domains.
The easiest way seems to be testing whether the HTML and Body tags have zero attributes (plus only-child and class selection on the image tag) because the structure of most documents which haven't been generated by the browser won't start as simply as <html><body><img class="...
But all I can find is how to exclude a specific attribute, not all of them.
I've tried the following with no success:
[] {
color: blue;
}
[*] {
color: red;
}
<p>Clean element with no attributes</p>
<p class="has-class">Has class attribute</p>
<p id="has-id">Has ID attribute</p>
<p data-has-data-attribute="">Has data attribute</p>
The only remaining option I can come up with is just policing the standard attributes one would see ("class", "style", "name", "lang", etc.), but that's a lengthy and ever-changing list, notwithstanding the numerous non-standard ones.
A selector that matches a tag without attributes doesn't currently exist.
I read through the latest CSS selector reference and couldn't find a selector that does what you wish.
You can't use an asterisk in the attribute selector to select everything unfortunately. These two railroad diagrams represent what is allowed:
So your first two attempts are invalid, and the valid empty string seems to have no effect:
[] {
color: blue;
}
[*] {
color: red;
}
[""] { /* Seems to select nothing, rather than 'no attribute' */
color: magenta;
}
<p>Clean element with no attributes</p>
<p class="has-class">Has class attribute</p>
<p id="has-id">Has ID attribute</p>
<p data-has-data-attribute="">Has data attribute</p>
I can't come up with any possible hack that doesn't involve JavaScript. I will edit this answer if I figure out a solution.

Select all elements with a certain color?

Is there a selector that can select all elements with a certain color? I want to change all text with color: #1a0dab to color:00b0f4.
If the styles are defined inline, you can do this:
[style*="#1a0dab"] {
color: #00b0f4 !important;
}
Demo:
[style*="#1a0dab"] {
color: #00b0f4 !important;
}
<p style="color: #1a0dab">paragraph 1</p>
<p>paragraph 2</p>
<p style="color: #1a0dab">paragraph 3</p>
There's no pure CSS way of doing this if the original styles aren't defined inline.
If you have access to JavaScript, you can do something like the following, though performance will probably be poor if your page has a lot of elements or you need to run the function frequently:
[...document.querySelectorAll('*')]
.filter(el => getComputedStyle(el).color === 'rgb(26, 13, 171)')
Note that you need to use the RGB representation, not the hex version, to check equality.
Here's a demo of the latter approach:
[...document.querySelectorAll('*')]
.filter(el => getComputedStyle(el).color === 'rgb(26, 13, 171)')
.forEach(el => el.style.color = '#00b0f4')
.has-color {
color: #1a0dab;
}
<p class="has-color">paragraph 1</p>
<p>paragraph 2</p>
<p class="has-color">paragraph 3</p>
There is no such selector available in Javascript/jQuery. Perhaps you can:
1 - Update the CSS files and find/replace all instances instead
2 - Add a class to all the required elements and then use the class to target them.
You should make a list of all the tags you need to change color and then with jquery give a unique color change order

How to target CSS :last-of-type of consecutive elements (not ALL within a parent element)

Maybe this is not possible in CSS3 but I'm trying to automatically insert comma separators when there is multiple consecutive instances of footnotes within a paragraph.
The problem occurs when there is another footnote later on in the paragraph. You'll notice in Example 2 that the comma get's inserted after Footnote 2.
I've tried to switch it around and use first-child but this just ends in a reverse of the same problem.
sup:not(:first-child)::before {
content: ",";}
sup:last-child::before {
content: "";
}
Anyone know of a way to target the last-of-type when it's succeeded by any other content other than another of the same type?
sup:after {
content: ",";
}
sup:last-of-type:after {
content: "";
}
<h2>Example 1</h2>
<p>lorem upsum<sup>1,2</sup></p>
<h2>Example 2</h2>
<p>lorem upsum<sup>1,2</sup> flotsam jetsum<sup>3</sup></p>
You already have the answer: all you need to do is remove ALL your CSS as it's practically doing nothing.
sup:after {
content: ",";
}
sup:last-of-type:after {
content: "";
}
In your html, your code is <sup>1,2</sup> , which means you are already manually inputting the , for multiple values within <sup>.
That particular , within a <sup> with multiple values is not being generated by the above CSS but rather, is there only because you are manually typing it in.
In a <p> with only a single <sup>, the reason why it does not have a , is because of your class sup:last-of-type:after. Since that there is only a single instance of <sup> it is considered the last one too, thus, it adds content of "" to the end of it. Which once again is doing nothing since by default it's empty.
<h2>Example 1</h2>
<p>lorem upsum<sup>1,2</sup></p>
<h2>Example 2</h2>
<p>lorem upsum<sup class="sup-multiple">1,2</sup> flotsam jetsum<sup>3</sup></p>

:target behaviour but on :hover in CSS

Consider the w3schools example of the :target selector:
<!DOCTYPE html>
<html>
<head>
<style>
:target {
border: 2px solid #D4D4D4;
background-color: #e5eecc;
}
</style>
</head>
<body>
<h1>This is a heading</h1>
<p>Jump to New content 1</p>
<p>Jump to New content 2</p>
<p>Click on the links above and the :target selector highlight the current active HTML anchor.</p>
<p id="news1"><b>New content 1...</b></p>
<p id="news2"><b>New content 2...</b></p>
<p><b>Note:</b> Internet Explorer 8 and earlier versions do not support the :target selector.</p>
</body>
</html>
When you click on the anchor referencing another element it styles thep with the corresponding id.
I want the effect of :target but on hover instead. how is this done?
how do you style the thing that href points to in the page on hover?
if this is not possible. what is the best-performing javascript solution?
Because CSS selectors can only traverse from an earlier element to a later sibling, descendant or descendant of a sibling (and cannot select parent, or previous-sibling, elements), this cannot be done with CSS. As hovering the <a> to style the later :target-ed elements would first require traversing to the parent from the hovered-<a> element.
To do this with JavaScript, then, I'd suggest:
// a named function to toggle the highlighting of the
// targeted element:
function highlightTarget(event) {
// the 'event' is passed automagically from the
// addEventListener() method; as is the 'this'
// which is the element to which the event-handler
// (this function) was bound:
// using getAttribute() to get the value of the attribute,
// instead of 'this.href' which would get the absolute URL,
// replacing the leading '#' character with an empty string:
var id = this.getAttribute('href').replace(/^#/, ''),
// getting the element with that id:
target = document.getElementById(id);
switch (event.type) {
// if this is the mouseenter event we add the 'highlight'
// class-name:
case 'mouseenter':
target.classList.add('highlight');
break;
// on 'mouseleave' we remove the class-name:
case 'mouseleave':
target.classList.remove('highlight');
break;
}
}
// iterating over the NodeList returned by
// document.getElementsByTagName(), using
// Array.prototype.forEach():
Array.prototype.forEach.call(document.getElementsByTagName('a'), function(a) {
// if the href attribute (not property) begins with a '#':
if (a.getAttribute('href').indexOf('#') === 0) {
// we bind the highlightTarget function to handle
// both the 'mouseenter' and 'mouseleave' events:
a.addEventListener('mouseenter', highlightTarget);
a.addEventListener('mouseleave', highlightTarget);
}
});
.highlight {
background-color: red;
}
<h1>This is a heading</h1>
<p>Jump to New content 1
</p>
<p>Jump to New content 2
</p>
<p>Click on the links above and the :target selector highlight the current active HTML anchor.</p>
<p id="news1"><b>New content 1...</b>
</p>
<p id="news2"><b>New content 2...</b>
</p>
<p><b>Note:</b> Internet Explorer 8 and earlier versions do not support the :target selector.</p>
It is worth noting, though, that the CSS Selectors Module, Level 4, has a proposed solution, the reference-combinator, to address this:
The following example highlights an element when its is focused or hovered-over:
label:matches(:hover, :focus) /for/ input, /* association by "for" attribute */
label:matches(:hover, :focus):not([for]) input { /* association by containment */
box-shadow: yellow 0 0 10px;
}
Which suggests that the correct syntax (which, currently of course, does not work) may be:
a:matches(:hover) /href/ p {
background-color: red;
}
References:
CSS:
Reference combinator (E:matches(:hover) /href/ p).
JavaScript:
Array.prototype.forEach().
Element.getAttribute().
EventTarget.addEventListener().
Function.prototype.call().
Guide to JavaScript Regular Expressions.
String.prototype.indexOf().
String.prototype.replace().
switch () {...} operator.
For Info:
In CSS if link is ahead and adjacent to the target or target's parent, then you could do something similar:
[href="#news1"]:hover ~#news1,
[href="#news2"]:hover ~#news2{
border: 2px solid #D4D4D4;
background-color: #e5eecc;
}
<h1>This is a heading</h1>
Jump to New content 1
Jump to New content 2
<p>hover link and see target element highlight via <code>[href="#target] ~#target </code></p>
<p id="news1"><b>New content 1...</b></p>
<p id="news2"><b>New content 2...</b></p>
<p><b>Note:</b> links must be ahead and adjacent to target or parents target in order to work.</p>
To go further and understand ,See: http://www.w3.org/TR/css3-selectors/#attribute-representation
and notice those too : http://www.w3.org/TR/css3-selectors/#adjacent-sibling-combinators & http://www.w3.org/TR/css3-selectors/#general-sibling-combinators

CSS selector based on a:target

This is my HTML:
<p class="define"><a class="term" href="#jump" name="jump">jump</a> - Some description</p>
When the browser jumps to #jump I want to highlight the .define class. If I do;
a.term:target { background-color: #ffa; -webkit-transition: all 1s linear; }
I of course only highlight the a. How do I modify this to complete p? I tried a couple of variants like the one below, but none of them work.
a.term:target .define { stuff here }
a.term:target p.define { stuff here }
a.term:target p { stuff here }
jsFiddle: http://jsfiddle.net/vVPPy/
You can't modify the parent of an element using css. You will have to use a javascript alternative.
You will not be able to determine where the user is on the page using CSS. This can be accomplished with JavaScript - If you're not trying to reinvent the wheel, I'd recommend using Bootstrap's ScrollSpy.
Your <p> tag isn't the target of anything. If it were:
<p class="define" id="something">
<a class="term" href="#something" name="jump">jump</a> - blah
</p>
You could style it like so:
a.term:target { background-color: #ffa; }
but that has nothing to do with the <a> actually being clicked on. You'll need to use an onclick handler for that, ideally adding a class to the target and styling based on that class.

Resources