How to Add Content using :after? - css

I want to add some text after this using CSS:
div#option-box-ymq-variant-1.ymq-options-box ymq-options-box-15 ymq-shopify-option-box :after {
content: "Testing";
}
<div class="ymq-options-box ymq-options-box-15 ymq-shopify-option-box " id="option-box-ymq-variant-1" data-type="15" data-id="-ymq-variant-1" data-ymq-add-to-cart="1" data-name="ymq-option2" data-label="Modo de Color" data-onetime="0" data-class="ymq-attrib-ymq-variant-1"
name="option-box-ymq-variant-Modo de Color">Div</div>
Sorry if this is a basic question, I'm new to coding.

To match multiple classes you need to use . instead of (space):
div#option-box-ymq-variant-1.ymq-options-box.ymq-options-box-15.ymq-shopify-option-box::after {
content: "Testing";
}
<div class="ymq-options-box ymq-options-box-15 ymq-shopify-option-box " id="option-box-ymq-variant-1" data-type="15" data-id="-ymq-variant-1" data-ymq-add-to-cart="1" data-name="ymq-option2" data-label="Modo de Color" data-onetime="0" data-class="ymq-attrib-ymq-variant-1"
name="option-box-ymq-variant-Modo de Color">
Your previous selector:
div#option-box-ymq-variant-1.ymq-options-box ymq-options-box-15 ymq-shopify-option-box :after
Was selecting the after pseudo element of nothing that was a child of an element of type ymq-shopify-option-box (which doesn't exist) etc. as a space in a selector is a descendant combinator
Note: Use two colons for pseudo elements
This is the current way of differentiating a pseudo element (like before and after) from a pseudo class.
Note: Pseudo element text is for styling and not content
Adding a bit of text or styling in pseudo elements can be very useful, but be aware that the text is not part of the DOM and may get missed for example by screen readers so don't totally rely on them to convey vital information on their own, they are more of a useful embellishment.

you select wrong
div#option-box-ymq-variant-1:after{
content: 'test';
}

Related

Testing contents of after CSS selector in protractor

In my HTML I have element such as below
HTML:
<hmtl>
<head>
<style>
label::after {
content: " *"
}
</style>
</head>
<body>
<label> I'm mandatory</label>
</body>
</hmtl>
So what gets displayed on browser is:
I'm mandatory *
Query Selector
>getComputedStyle(document.querySelector('label')).content
<"normal"
So I see normal instead of *.
I can't see where is normal coming from. Is this the correct way to test content of ::after CSS selector?
I want to test that there's a "*" after the label, but can't seem to be able to get the value of "content" property correctly. Once I'm able to find it in using browser DOM API, I'd eventually want to test it in protractor.
Update
I found the answer at - Selenium WebDriver get text from CSS property "content" on a ::before pseudo element.
Now the question remains how I would test this on protractor.
Window.getComputedStyle()
The Window.getComputedStyle() method returns an object containing the values of all CSS properties of an element, after applying active stylesheets and resolving any basic computation those values may contain. Individual CSS property values are accessed through APIs provided by the object, or by indexing with CSS property names.
Syntax:
var style = window.getComputedStyle(element [, pseudoElt]);
element
The Element for which to get the computed style.
pseudoElt (Optional)
A string specifying the pseudo-element to match. Omitted (or null) for real elements.
The returned style is a live CSSStyleDeclaration object, which updates automatically when the element's styles are changed.
You can find a related discussion in WebDriver select element that has ::before
Usage with pseudo-elements
getComputedStyle() can pull style info from pseudo-elements (such as ::after, ::before, ::marker, ::line-marker.
As per the HTML, the <style> is as follows:
<style>
label::after {
content: " *"
}
</style>
Implemented as:
<label> I'm mandatory</label>
To retrieve you need to:
var label = document.querySelector('label');
var result = getComputedStyle(label, ':after').content;
console.log('the generated content is: ', result); // returns ' *'
Reference
CSS Pseudo-Elements Module Level 4
const label = document.querySelector('label'); // "normal";
console.log(label);
const labelAfter = getComputedStyle(label, ':after').content;
console.log(labelAfter == "normal");
label::after {
content: " *"
}
<label> I'm mandatory</label>
Since my question was specifically w.r.t protractor I'm posting the solution that I got working. Coming to the part I was stuck initially - why do I get "normal" instead of " *"
>getComputedStyle(document.querySelector('label')).content
<"normal"
So earlier I was unaware that ::after creates a pseudo child element inside the label element.
Inspecting <label> element in Chrome shows the below HTML
<label>
I'm mandatory
::after
</label>
If I click<label> element and checked the Computed tab, I could see that the value for content property is normal.
However, if I click on ::after pseudo-element, I can see in the Computed tab the value for content property is " *".
As mentioned in the other answers getComputedStyle() with the pseudo element as second parameter, is the only way to get value of CSS property for "::after". The crux of the problem is that protractor does not have an equivalent for getComputedStyle(), so we have to rely upon browser.executeScript() as shown below:
let labelHeader = 'I'm mandatory *';
// Passing label element separately as in the real test case, it would be extracted from parent
// enclosing element and need to be able to pass it as a parameter to browser.executeScript().
let label = element(by.css('label'));
browser.executeScript("return window.getComputedStyle(arguments[0], ':after').content",
label)
.then ((suffixData: string) => {
// suffixData comes out to be '" *"', double quotes as part of the string.
// So get rid of the first and last double quote character
suffixData = suffixData.slice(1, suffixData.length - 1);
labelText += suffixData;
expect(labelText).toBe(labelHeader);
});

:empty doesn't work if there's blank spaces?

Trying to find a pseudo class that'll target a <div> like this:
<div class="nav-previous">
</div>
I've tried :blank and :empty but neither can detect it. Is it just not possible to do?
https://jsfiddle.net/q3o1y74k/3/
:empty alone is enough.
By the current Selectors Level 4 specification, :empty can match elements that only contain text nodes that only contain whitespace as well as completely empty ones. It’s just there aren’t many that support it as per the current specification.
The :empty pseudo-class represents an element that has no children except, optionally, document white space characters.
From the MDN:
Note: In Selectors Level 4, the :empty pseudo-class was changed to act like :-moz-only-whitespace, but no browser currently supports this yet.
The :-moz-only-whitespace CSS pseudo-class matches elements that only contain text nodes that only contain whitespace. (This includes elements with empty text nodes and elements with no child nodes.)
As the others mentioned, this isn't possible with CSS yet.
You can check to see if there's only whitespace with JavaScript however. Here's a simple JS only solution, "empty" divs that match are blue, while divs that have text are red. Updated to add an empty class to the empty divs, which would allow you to target them easily with the selector .empty in your CSS.
The JS only "empty" comparison would look like this:
if(element.innerHTML.replace(/^\s*/, "").replace(/\s*$/, "") == "")
And if you're using jQuery it would be a bit easier:
if( $.trim( $(element).text() ) == "" ){
var navs = document.querySelectorAll(".nav-previous");
for( i=0; i < navs.length; i++ ){
if(navs[i].innerHTML.replace(/^\s*/, "").replace(/\s*$/, "") == "") {
navs[i].style.background = 'blue';
navs[i].classList.add( 'empty' );
} else {
navs[i].style.background = 'red';
}
}
.nav-previous {
padding: 10px;
border: 1px solid #000;
}
.nav-previous.empty {
border: 5px solid green;
}
<div class="nav-previous">
</div>
<div class="nav-previous">Not Empty </div>
The problem with your approach is that your container is not actually empty.
The :empty pseudo-class represents an element that has no children at
all. In terms of the document tree, only element nodes and content
nodes (such as DOM text nodes, CDATA nodes, and entity references)
whose data has a non-zero length must be considered as affecting
emptiness;
As you have empty spaces this pseudo class will not do the trick.
The :blank pseudo class should be the right one, because this is its definition:
This blank pseudo-class matches elements that only contain content
which consists of whitespace but are not empty.
the problem is that this pseudo class isn't implemented by any browser yet as you can check in the link below. So you will need to wait until it get implemented to be able to use this selector.
This pretty much explains the behavior you are facing
https://css4-selectors.com/selector/css4/blank-pseudo-class/
The best approach here is just to be sure that your div will actually be empty, so your approach will work.
the best that you can do is to define an empty class like this:
.empty{
display:none;
}
and then add this JS code here, it will append the empty class to your blank items:
(function($){
$.isBlank = function(html, obj){
return $.trim(html) === "" || obj.length == 0;
};
$('div').each(function() {
if($.isBlank(
$(this).html(),
$(this).contents().filter(function() {
return (this.nodeType !== Node.COMMENT_NODE);
})
)) {
$(this).addClass('empty');
}
});
})(jQuery);
check it working here,
https://jsfiddle.net/29eup5uw/
You just can't without JavaScript/jQuery implementation.
:empty selector works with empty tags (so without even any space in them) or with self-closing tags like <input />.
Reference: https://www.w3schools.com/cssref/css_selectors.asp
If you want to use JavaScript implementation, I guess here you will find the answer: How do I check if an HTML element is empty using jQuery?
:empty indeed only works for totally empty elements. Whitespace content means it is not empty, a single space or linebreak is already enough. Only HTML comments are considered to be 'no content'.
For more info see here: https://css-tricks.com/almanac/selectors/e/empty/
The :blank selector is in the works, it will match whitespace, see here: https://css-tricks.com/almanac/selectors/b/blank/. But it seems to have no browser support yet.
Update:
See here for possible solutions to this involving jQuery.

Targetting element:only-child with no sibling text node [duplicate]

I would like to select anchor tags only when they're completely by themselves, that way I can make those look like buttons, without causing anchors within sentences to look like buttons. I don't want to add an extra class because this is going within a CMS.
I originally was trying this:
article p a:first-child:last-child {
background-color: #b83634;
color: white;
text-transform: uppercase;
font-weight: bold;
padding: 4px 24px;
}
But it doesn't work because text content isn't considered as criteria for :first-child or :last-child.
I would like to match
<p><a href='#'>Link</a></p>
but not
<p><a href='#'>Link</a> text content</p>
or
<p>text content <a href='#'>Link</a></p>
Is this possible with CSS?
The simple answer is: no, you can't.
As explained here, here and here, there is no CSS selector that applies to the text nodes.
If you could use jQuery, take a look at the contains selector.
Unfortunately no, you can't.
You have to use JS by it self or any librady of it to interact with content of elements and found where is each element in the content.
If you wish me to update my answer with a JS example prease ask for it.
I don't think it's generally possible, but you can come close. Here are some helpful places to start:
The Only Child Selector which would allow you to select all a elements which have no siblings like so a:only-child {/* css */}. See more here. (Also see edit)
The Not Selector which would allow you to exclude some elements perhaps using something along the lines of :not(p) > a {/* css */} which should select all anchors not in a paragraph. See some helpful information here.
Combining selectors to be as specific as possible. You might want all anchors not in an h1 and all anchors not in a p.
Example:
The final product might look like this:
a:only-child, :not(p) > a {/* css */}
This should select all anchors that are only children and anchors that are not in a paragraph.
Final note:
You may want to consider making the buttons actual button or input tags to make your life easier. Getting the HTML right first usually makes the CSS simpler.
Edit: the only child ignores the text, so that's pretty much useless here. I guess it's less doable than I thought.
jQuery Code Example:
// this will select '<p><a></a></p>' or '<p><a></a>text</p>'
// but not '<p><a></a><a></a></p>'
$('p').has('a:only-child').each(function() {
const p = $(this); // jQuerify
let hasalsotext = false;
p.contents().each(function(){
if ((this.nodeType === 3) && (this.nodeValue.trim() !== "")) {
hasalsotext = true;
return false; // break
}
});
if (!hasalsotext) {
$('a', p).addClass('looks-like-a-button');
}
});

Add line break to ::after or ::before pseudo-element content

I do not have access to the HTML or PHP for a page and can only edit via CSS. I've been doing modifications on a site and adding text via the ::after or ::before pseudo-elements and have found that escape Unicode should be used for things such as a space before or after the added content.
How do I add multiple lines in the content property?
In example the HTML break line element is only to visualize what I would like to achieve:
#headerAgentInfoDetailsPhone::after {
content: 'Office: XXXXX <br /> Mobile: YYYYY ';
}
The content property states:
Authors may include newlines in the generated content by writing the "\A" escape sequence in one of the strings after the 'content' property. This inserted line break is still subject to the 'white-space' property. See "Strings" and "Characters and case" for more information on the "\A" escape sequence.
So you can use:
#headerAgentInfoDetailsPhone:after {
content:"Office: XXXXX \A Mobile: YYYYY ";
white-space: pre; /* or pre-wrap */
}
http://jsfiddle.net/XkNxs/
When escaping arbitrary strings, however, it's advisable to use \00000a instead of \A, because any number or [a-f] character followed by the new line may give unpredictable results:
function addTextToStyle(id, text) {
return `#${id}::after { content: "${text.replace(/"/g, '\\"').replace(/\n/g, '\\00000a')} }"`;
}
Nice article explaining the basics (does not cover line breaks, however).
A Whole Bunch of Amazing Stuff Pseudo Elements Can Do
If you need to have two inline elements where one breaks into the next line within another element, you can accomplish this by adding a pseudo-element :after with content:'\A' and white-space: pre
HTML
<h3>
<span class="label">This is the main label</span>
<span class="secondary-label">secondary label</span>
</h3>
CSS
.label:after {
content: '\A';
white-space: pre;
}
I had to have new lines in a tooltip. I had to add this CSS on my :after :
.tooltip:after {
width: 500px;
white-space: pre;
word-wrap: break-word;
}
The word-wrap seems necessary.
In addition, the \A didn't work in the middle of the text to display, to force a new line.
worked. I was then able to get such a tooltip :
You may try this
#headerAgentInfoDetailsPhone
{
white-space:pre
}
#headerAgentInfoDetailsPhone:after {
content:"Office: XXXXX \A Mobile: YYYYY ";
}
Js Fiddle
For people who will going to look for 'How to change dynamically content on pseudo element adding new line sign" here's answer
Html chars like
will not work appending them to html using JavaScript because those characters are changed on document render
Instead you need to find unicode representation of this characters which are U+000D and U+000A so we can do something like
var el = document.querySelector('div');
var string = el.getAttribute('text').replace(/, /, '\u000D\u000A');
el.setAttribute('text', string);
div:before{
content: attr(text);
white-space: pre;
}
<div text='I want to break it in javascript, after comma sign'></div>
Hope this save someones time, good luck :)
Add line break to ::after or ::before pseudo-element content
.yourclass:before {
content: 'text here first \A text here second';
white-space: pre;
}
Found this question here that seems to ask the same thing: Newline character sequence in CSS 'content' property?
Looks like you can use \A or \00000a to achieve a newline
<p>Break sentence after the comma,<span class="mbr"> </span>in case of mobile version.</p>
<p>Break sentence after the comma,<span class="dbr"> </span>in case of desktop version.</p>
The .mbr and .dbr classes can simulate line-break behavior using CSS display:table. Useful if you want to replace real <br />.
Check out this demo Codepen: https://codepen.io/Marko36/pen/RBweYY,
and this post on responsive site use: Responsive line-breaks: simulate <br /> at given breakpoints.

Is it possible to show the total number of elements in the content css property?

I'm using the following css to display a step counter:
:before {
content: "step " counter(fieldsets);
counter-increment: fieldsets;
/* Some more css */
}
But I was wondered if it was possible to display the total number of elements as well, like so:
:before {
content: "step " counter(fieldsets) " of " total_number_of_fieldsets;
counter-increment: fieldsets
/* Some more css */
}
I would love it to be a pure css solution, is that possible?
Unless you have something else that calculate the total_number_of_fieldsets count in the CSS, it is not possible.
See this fiddle: http://jsfiddle.net/EawLA/
You can show the total :after
Note that this will not work in IE<9 as pseudo elements are not supported
CSS cannot inspect the DOM or use variables, therefore it cannot pull up this inforamtion.

Resources