I'm trying to change all the titles, i.e. h1, h2, h3... to be uppercase using JavaScript.
the white cat should be THE WHITE CAT.
The method will be placed in a seperate .js file.
In JavaScript you need to get reference the object using document.getElementById or document.getElementsByClassName. After that you can style the element by accessing the style property of the object, OR just set the content to be uppercase using the built in toUpperCase() function that JavaScript has.
var header = document.getElementById("myHeader");
header.innerHTML = header.innerHTML.toUpperCase();
<h1 id="myHeader">Hello, world</h1>
HOWEVER
The easier solution is to just set a class on the whole header object, and use
.upperCaseHeader { text-transform: uppercase}
Or, if you know that all the header elements on your page will be uppercase, use;
h1,h2,h3,h4,h5 { text-transform: uppercase; }
in a CSS file.
EDIT: On OP's request the code is slightly changed to change the text to uppercase on button click
The function here will find all the tags of type h1 through h6 using getElementsByTagName and set all the text in them to uppercase, as you requested. Again, I would rather add a class with text-transform uppercase, and dynamically add and remove this class, but since you have very specific needs, I am posting this alternative solution here now.
Here is a working pen as well
function setUppercase() {
var tags = ["h1", "h2", "h3", "h4", "h5", "h6"];
for (var i = 0; i < tags.length; i++) {
var allTagsOfType = document.getElementsByTagName(tags[i]);
for (var j = 0; j < allTagsOfType.length; j++) {
allTagsOfType[j].innerText = allTagsOfType[j].innerText.toUpperCase();
}
}
}
<h1>Hello</h1>
<h2>I am going</h2>
<h3>to be</h3>
<h4>uppercase</h4>
<h5>soon</h5>
<h6>tiny text</h6>
<button onclick="setUppercase()">Set uppercase</button>
in your style.css
h2 {
text-transform: uppercase;
}
Perhaps something like this?
ref: https://www.w3schools.com/jsref/jsref_touppercase.asp
var text = $('h2').text();
var res = text.toUpperCase();
$('h2').text(res);
Edit--
Or you can do everything through JS and append the element. the `` are ES6 string literals.
var text = "The White Cat";
var res = text.toUpperCase();
var uppercase = `<h2>${res}</h2>`;
$('body').append(uppercase);
Try this inline styling:
<h2 style="text-transform: uppercase"> The White Cate </h2>
As we all know inline styles are not good practice and they are not compatible with e.g. the Content Security Policy.
This is what I want to achieve without inline styles:
<?php
$spacer_height = 390; // this is a dynamic value from user input could be any integer
?>
<div class="spacer" style="height:<?php echo $spacer_height; ?>"></div>
This is what I want:
HTML:
<?php
$spacer_height = 390; // this is a dynamic value from user input
?>
<div class="spacer spacerheight-<?php echo $spacer_height; ?>" data-height="<?php echo $spacer_height; ?>"></div>
External Stylesheet:
.spacer {
height: spacer_height + "px"; // this line is dummy code
}
Is where a way to achieve this with CSS only. No JavaScript. No Polyfill.
What I have already found is this 5 year old question: CSS values using HTML5 data attribute
However is there a solution meanwhile or is there a CSS solution not using attributes? Is there at least a solution for integers?
Edit: Even a working polyfill may be a welcome answer if there is no other solution.
As you can't do this CSS only (yet, since the attr() function only returns string value), here is a simple script that will do something similar what attr() does, though this parse the data and sets it dynamically using cssText.
Let me know if I got this right
window.addEventListener("load", function() {
var mb = isMobile();
var el = document.querySelectorAll('[data-css]');
for (i = 0; i < el.length; i++) {
var what = el[i].getAttribute('data-css');
if (what) {
what = what.split(',');
el[i].style.cssText = what[0] + ': ' + ((mb) ? what[2] : what[1]) + 'px';
}
}
});
function isMobile() {
//function that check if user is on mobile etc.
return false; // return false for this demo
}
html, body {
margin: 0;
}
div {
background-color: lightgreen;
padding: 10px 0;
height: auto;
box-sizing: border-box;
}
div ~ div {
margin-top: 10px;
}
<div data-css="height,60,30"></div>
<div></div>
<div></div>
<div data-css="height,60,30"></div>
<div></div>
Another option would be to run something server side, where you simply create the CSS rule and class and insert it into CSS file and markup respectively, before sending to the client
You might consider moving the dynamic part from being inline to being referenced in a <style>.
<style>
.spacer {
height:<?php echo $spacer_height; ?>
}
</style>
<?php
$spacer_height = 390; // this is a dynamic value from user input could be any integer
?>
<div class="spacer"></div>
I need to target the last <a> element but with some conditionals.
In this case the text is created through a CMS which limit's me the option to add a class. I created a jsfiddle to show my problem. The last <a> must have an font awesome angle right in it's :after the other <a> elements not. I can't use something like :last-child a because the user/text writer doesn't have to write a link by default. There is also the possibility of another paragraph after the first. So nothing is default but the last <a> element which stands alone from the paragraph with some actual text must have an icon.
It's kinda hard to explain but the jsfiddle will explain itself so please take a look. it would be nice if there was a CSS solution. if not jQuery comes second.
Thanks in advance!
As far as I know it cannot be done using CSS alone.
How about JavaScript:
var element = document.getElementsByTagName("a");
for(var i=0; i < element.length; i++) {
var el = element[i]
var x = el.parentNode.innerText.length;
var y = el.innerText.length
if (x === y) {
el.classList.add('icon');
}
}
CSS:
.icon::after{
content: "\f105";
margin-left:5px;
font-family: FontAwesome;
background-color: transparent;
}
It adds an .icon class to all <a> elements which are not wrapped inline with text in the parent element.
You can target the last p tag.
p:last-of-type a::after{
content: "\f105";
margin-left:5px;
font-family: FontAwesome;
background-color: transparent;
}
I have a list of paths (for lack of a better word, maybe bread crumb trails describes them better). Some of the values are too long to display in their parent so I'm using text-overflow: ellipsis. The problem is that the important information is on the right, so I'd like the ellipsis to appear on the left. Something like this this ascii art:
----------------------------
|first > second > third |
|...second > third > fourth|
|...fifth > sixth > seventh|
----------------------------
Notice that the first row is short enough so it remains left aligned, but the other two are too long so the ellipsis appears on the left hand side.
I'd prefer a CSS only solution, but JS is fine if it can't be avoided. It's ok if the solution only works in Firefox and Chrome.
EDIT: At this point I'm looking for a work around for the bugs in Chrome that prevent it from rendering properly when a document is mixed RTL and LTR. That was all I really needed from the outset, I just didn't realize it.
How about something like this jsFiddle? It uses the direction, text-align, and text-overflow to get the ellipsis on the left. According to MDN, there may be the possibility of specifying the ellipsis on the left in the future with the left-overflow-type value however it's considered to still be experimental.
p {
white-space: nowrap;
overflow: hidden;
/* "overflow" value must be different from "visible" */
text-overflow: ellipsis;
width: 170px;
border: 1px solid #999;
direction: rtl;
text-align: left;
}
<p>first > second > third<br /> second > third > fourth > fifth > sixth<br /> fifth > sixth > seventh > eighth > ninth</p>
I finally had to crack and do something in JavaScript. I was hoping that someone would come up with a hail-mary CSS solution but people seem to just be up-voting the answer that should be correct if it weren't for the Chrome bugs. j08691 can have the bounty for his work.
<html>
<head>
<style>
#container {
width: 200px;
border: 1px solid blue;
}
#container div {
width: 100%;
overflow: hidden;
white-space: nowrap;
}
</style>
<script>
function trimRows() {
var rows = document.getElementById('container').childNodes;
for (var i=0, row; row = rows[i]; i++) {
if (row.scrollWidth > row.offsetWidth) {
var textNode = row.firstChild;
var value = '...' + textNode.nodeValue;
do {
value = '...' + value.substr(4);
textNode.nodeValue = value;
} while (row.scrollWidth > row.offsetWidth);
}
}
}
</script>
</head>
<body onload='trimRows();'>
<div id="container" >
<div>first > second > third</div>
<div>second > third > fourth > fifth > sixth</div>
<div>fifth > sixth > seventh > eighth > ninth</div>
</div>
</body>
</html>
Fiddle
Why not just using direction:rtl;
It's a little buggy, but maybe a point in the right direction
http://jsfiddle.net/HerrSerker/ZfbaD/50/
$('.container')
.animate({'width': 450}, 4000)
.animate({'width': 100}, 4000)
.animate({'width': 170}, 4000)
.container {
white-space: nowrap;
overflow: hidden; /* "overflow" value must be different from "visible" */
text-overflow: ellipsis;
width:170px;
border:1px solid #999;
direction:rtl;
}
.container .part {
direction:ltr;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<span class="part">second</span>
<span class="part">></span>
<span class="part">third</span>
<span class="part">></span>
<span class="part">fourth</span>
<span class="part">></span>
<span class="part">fifth</span>
<span class="part">></span>
<span class="part">sixth</span>
</div>
These solutions solve the problem with misinterpreted preceding or trailing weak or neutral BiDi characters such as /, \, ~, ., etc. (basically any punctuation or special characters).
CSS Solution
Use a combination of:
direction: rtl & ltr
unicode-bidi: bidi-override
p {
direction: rtl;
max-width: 180px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap; /* or pre (e.g. preserve multiple spaces) */
}
span {
direction: ltr;
unicode-bidi: bidi-override; /* or isolate, isolate-override, embed */
}
<p><span>/path/to/a/very/long/file.name</span></p>
<bdo> Solution
Another possibility uses the <bdo> Bidirectional Text Override element:
p {
max-width: 180px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap; /* or pre (e.g. preserve multiple spaces) */
}
<bdo dir="rtl">
<p>
<bdo dir="ltr">/path/to/a/very/long/file.name</bdo>
</p>
</bdo>
Using #Hemlocks, #Brian Mortenson and #Jimbo's solutions, I've built a jQuery plugin to solve this problem.
I've also added support to return the initial value using .html() rather than having it return the current innerHTML. Hopefully it will be useful to someone...
(function($) {
$.trimLeft = function(element, options) {
var trim = this;
var $element = $(element), // reference to the jQuery version of DOM element
element = element; // reference to the actual DOM element
var initialText = element.innerHTML;
trim.init = function() {
overrideNodeMethod("html", function(){ return initialText; });
trimContents(element, element);
return trim;
};
trim.reset = function(){
element.innerHTML = initialText;
return trim;
};
//Overide .html() to return initialText.
var overrideNodeMethod = function(methodName, action) {
var originalVal = $.fn[methodName];
var thisNode = $element;
$.fn[methodName] = function() {
if (this[0]==thisNode[0]) {
return action.apply(this, arguments);
} else {
return originalVal.apply(this, arguments);
}
};
};
var trimContents = function(row, node){
while (row.scrollWidth > row.offsetWidth) {
var childNode = node.firstChild;
if (!childNode)
return true;
if (childNode.nodeType == document.TEXT_NODE){
trimText(row, node, childNode);
}
else {
var empty = trimContents(row, childNode);
if (empty){
node.removeChild(childNode);
}
}
};
};
var trimText = function(row, node, textNode){
var value = '\u2026' + textNode.nodeValue;
do {
value = '\u2026' + value.substr(4);
textNode.nodeValue = value;
if (value == '\u2026'){
node.removeChild(textNode);
return;
}
}
while (row.scrollWidth > row.offsetWidth);
};
trim.init();
};
$.fn.trimLeft = (function(options){
var othat = this;
var single = function(that){
if (undefined == $(that).data('trim')) {
var trim = new $.trimLeft(that, options);
$(that).data('trim', trim);
$(window).resize(function(){
$(that).each(function(){
trim.reset().init();
});
});
}
};
var multiple = function(){
$(othat).each(function() {
single(this);
});
};
if($(othat).length>1)
multiple(othat);
else
single(othat);
//-----------
return this;
});
})(jQuery);
Initiate using:
//Call on elements with overflow: hidden and white-space: nowrap
$('#container>div').trimLeft();
//Returns the original innerHTML
console.log($('#test').html());
fiddle
Using a slightly more complex markup (using the bdi-tag and an extra span for the ellipsis), we can solve the problem fully in CSS, no JS required at all -- cross browser (IE, FF, Chrome) and including keeping punctuation marks to the right:
http://jsbin.com/dodijuwebe/1/edit?html,css,output
Granted, this is something of a hack, involving pseudo-element goodness. However, our team has been using this code in production and we haven't had any issues whatsoever.
The only caveats are: The height of the line needs to be fixed and the background color needs to be known explicitly (inherit won't work).
If you don't care the indexing of those texts, you could use this method (it reverses the text lines):
If you have in your texts other HTML elements besides <br> you need to make some arrangements to use this method.
HTML code:
<p>first > second > third<br/>
second > third > fourth <br>
fifth > sixth > seventh</p>
CSS code:
p{
overflow: hidden;
text-overflow: ellipsis;
unicode-bidi: bidi-override;
direction: rtl;
text-align: left;
white-space: nowrap;
width: 140px;
}
JavaScript code
[].forEach.call(document.getElementsByTagName("p"), function(item) {
var str = item.innerText;
//Change the operators
str = str.replace(/[<>]/g, function(char){ return ({"<" : ">", ">" : "<"})[char] });
//Get lines
var lines = str.split(/\n/);
//Reverse the lines
lines = lines.map(function(l){ return l.split("").reverse().join("") });
//Join the lines
str = lines.join("<br>");
item.innerHTML = str;
});
jsfiddle
Based on your edit:
At this point I'm looking for a work around for the bugs in Chrome
that prevent it from rendering properly when a document is mixed RTL
and LTR. That was all I really needed from the outset, I just didn't
realize it.
Have you looked into the unicode-bidi css property (see Sitepoint or W3C)? I actually just learned about this myself on another recent post. My guess is you would want to use the embed value for those pieces going the opposite direction to the main site. So in j08691's answer where it is direction: rtl add unicode-bidi: embed to the CSS. This should solve "mixed RTL and LTR" issues you are having.
I put some JavaScript together to regex out three items and add the ellipsis in where necessary. This does not explicitly look at how much text will fit in the box but if the box is fixed this may not be an issue.
<style>
p {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width:170px;
border:1px solid #999;
direction:rtl;
text-align:left;
}
</style>
<p>first > second > third<br />
second > third > fourth > fifth > sixth<br />
fifth < sixth < seventh < eighth < ninth</p>
<script>
var text = $( 'p' ).text(),
split = text.split( '\n' ),
finalStr = '';
for( i in split ){
finalStr = finalStr.length > 0 ? finalStr + '<br />' : finalStr;
var match = /(\w+\s?(<|>)?\s?){3}$/.exec( split[i] );
finalStr = finalStr + ( split[i].length > match[0].length ? '...' : '' ) + match[0];
}
$( 'p' ).empty().html( finalStr );
</script>
I'd like to tell the browser to assign certain CSS classes to elements matching a particular selector. Can I do it with pure CSS and if yes, how?
Example: I want all the h5 elements inside a div with id sidebar to have the class ui-corners-all
No, that isn't possible with pure CSS.
Only with JavaScript:
// jQuery
$("h5").addClass("ui-corners-all");
// Pure JavaScript
var elements = document.getElementsByTagName("h5");
for (var i=0; i<elements.length; i++)
{
var el = elements[i];
el.setAttribute( "class", el.getAttribute("class") + " ui-corners-all" );
}
There is no way to assign this value to those elements in pure CSS.
You would need to do:
#sidebar h5
{
}
Then copy all styles from ui-corners-all class into this.
Or alternatively, change your ui-corners-all CSS to:
.ui-corners-all, #sidebar h5
{
}
No, you can't. You can however use Javascript (jQuery recommended) to achieve this effect.