I'm looking for a (CSS-)way to apply the hover state to a part of my HTML text when another part is hovered over, the two parts sharing the same CSS class.
I have a bunch of text in HTML, divided into words. Each word is linked to a CSS class; two different words can be linked to the same class.
By example, if I take three words and two classes (classA, classB),
word1, word3 -> classA
word2 -> classB
I will write the following HTML code :
<span class=classA>word1</span>
<span class=classB>word2</span>
<span class=classA>word3</span>
My problem : I want to change the appearance of a group of words sharing the same class on mouse over.
I tried :
.classA {
color: red;
}
.classA:hover {
color: blue;
}
... but when the mouse goes over "word1", "word1" is highlighted, but not "word3" which shares the same class ("classA").
Any help would be appreciated !
The short answer is NO, you cannot do that with CSS only except if you go for the solutions I've shared with you below.
Use the adjacent selector to apply the :hover effect at the same time
.classA:hover + .classB + .classA {
color: blue;
}
Demo
But unfortunately this will only work if you :hover the first group element, as you cannot go back with CSS, the second way to do is use a wrapper element but again, this will be limited if you are having only 2 combination of classes where you want to apply styles to a single type of class.
.wrapper_class:hover .classA {
color: blue;
}
Demo 2
.classA:hover {
color: blue;
}
This code applies only to elements that have class=classA AND are under the mouse..
I think it would be simpler to use Javascript:
var span = document.getElementsByClassName('classA');
var i = 0;
while(i < span.length){
span[i].onmouseover = function change(){
var i = 0;
while(i < span.length){
span[i].style.color = 'blue';
i++;
}
}
span[i].onmouseout = function change(){
var i = 0;
while(i < span.length){
span[i].style.color = 'red';
i++;
}
}
i++;
}
http://jsfiddle.net/fa7d0/Bt8eN/1/
Related
I need to have 3 classes as follow:
.class-4, .class-5, .class-6 {
color: pink;
}
And it works perfectly.
Let's say I need the same but for 100:
.class-4, .class-5, .... .class-100 {
color: pink;
}
Is there anything similar to this or any other way to do this which I can use.
.class->3<101 {
color: pink;
}
To get the same result without writing 97 times the class and the comma?
There is nothing in pure CSS which will do this, but you could use JavaScript to create a stylesheet for you which has all that tedious repetition created automatically.
In this snippet you say what the ends of the class ranges are and what styling is to be put in each of the ranges.
If there is a range which you don't want to alter then you still need to include it but make its styles string just an empty string.
The snippet runs through each of the ranges creating the relevant style sheet entries and puts them in a style element in the head element of the document.
A few fairly random divs are shown here just to test that we are hitting the right ranges.
const rangeEnds = [4, 20, 35, 41, 48, 100];
const styles = ['color: pink;', 'color: red; background-color: black;', 'color: green;', 'color: yellow;', 'color: blue;', 'color: black; background: pink;'];
let lastRangeEnd = 0;
const styleEl = document.createElement('style');
for (let i = 0; i < rangeEnds.length; i++) {
for (let j = lastRangeEnd + 1; j < rangeEnds[i]; j++) {
styleEl.innerHTML += '.class-' + j + ',';
}
styleEl.innerHTML += '.class-' + rangeEnds[i] + '{' + styles[i] + '}';
lastRangeEnd = rangeEnds[i];
}
document.querySelector('head').append(styleEl);
<!doctype html>
<html>
<head>
<title>Classes</title>
</head>
<body>
<div class="class-1">ABCD</div>
<div class="class-19">ABCD</div>
<div class="class-21">ABCD</div>
<div class="class-40">ABCD</div>
<div class="class-41">ABCD</div>
<div class="class-48">ABCD</div>
<div class="class-100">ABCD</div>
</body>
If all elements will have the same property which is {color:pink}
You can create only one class (lets call it .pink)
.pink {
color: pink;
}
and then you can simply give your elements the .pink class.
One of class attribute's main purpose is to define a shared style reference name. It is rather not a very good practice to want to reference multiple class references and let them share the same styling.
The best way to get around this is to have a common class attribute name YourClassName. This way, any element you want the styling applied to can have that class appended to its class attribute through element.classList.add(YourClassName) with JS. And, that would solve all the hussle of having to worry about putting multiple classe names and I cannot think of any 1 situation that would force you to declare each element class separated by commas provided that they are to receive the same styling.
The OP asks if it’s possible to have a ‘number range’ (array) at the end of CSS classes that shares the same name, but ending on 1, 2, 3, etc.
As #zer00ne pointed out; You can target multiple classes with one "class". When defining your class selector - leave out the numbers, but make the class name unique.
So, if the class names are i.e. my-row-class-1, my-row-class-2, etc., write the selector like this;
[class^="my-row-class-"] {
color: pink;
}
Pro tip: Instead of using class^= selector, it's possible to do this for id^= as well - and more. Check out the MDN web docs for more info.
I have some <pre> blocks.
Would it be possible, using just CSS, to highlight single lines when hovering over them?
== Update ==
Here is some sample code:
<pre>
#include <stdio.h>
int main()
{
printf("Hello World");
return 0;
}
</pre>
When lines become longer it would be useful to have them highlighted when hovering.
The source file can't be read via PHP, or I'd split it into separate <pre> lines, with a trivial pre:hover CSS.
pre:nth-child is not a solution, because code lines are not "children" in the CSS sense.
pre:first-line works, but of course just for the first line.
== Update 2 ==
Since CSS seems to be limited to first-line, and thanks to Zeke suggestion, I found an almost simple way to have what I want.
HTML:
<pre id="raw">
#include <stdio.h>
int main()
{
printf("Hello World");
return 0;
}
</pre>
<!-- 1×1 transparent PNG for the onload -->
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP4/x8AAwAB/2+Bq7YAAAAASUVORK5CYII=" onload="PreHover()" />
CSS:
#pre div:hover {
background: #ff0;
}
Vanilla Javascript:
function PreHover() {
var output = '';
var preBox = document.getElementById('raw');
var txt = preBox.innerHTML.split('\n');
for(var x=0;x<txt.length-1;x++) {
output = output + '<div>'+txt[x]+'</div>';
}
preBox.innerHTML = output;
}
JSFiddle here
This will help you wrap div for each line
var txt = $('pre').html().split("\n");
var output = "";
for(var x=0;x<txt.length-1;x++)
output = output + "<div>"+txt[x]+"</div>";
}
$('pre').html(output);
You can write one line css then for highlighting:
pre div:hover { background-color: rgba(0,0,0,0.2); }
Demo here
Note: This requires jQuery
Optional: Add white-space:nowrap to prevent wrapping each line
Why do this?
Because if just have <pre>, it will be a DOM element containing just text inside it, on which you can make changes as a whole, and not line by line.
To have much better control over every line, build a new DOM element by manipulating the text contained in <pre> with pre containing many div each of which contains one line of text. And now you can master each and every div
I'm trying to auto-number each line that will be generated while displaying a
<p> element.
Perhaps using counters in CSS?
I'm looking for something along the lines of p:first-line, except for every line of the <p> element
something like:
p:each-line {
counter-increment line_num;
}
p:each-line:before {
counter(line_num) " " ACTUAL-LINE;
}
Can I do this with simple CSS code? How else could I achieve this?
I have an element called message, and I don't know in advance how many lines
of actual text will be formatted using that element style. If I change the
max-width for example and that forces more/fewer lines, I'd like this to automatically
number correctly the actual lines in the element.
/* set up the speech bubbles */
p.message {
position:relative;
padding:5px 10px;
border:2px solid rgb(74,77,82);
border:2px solid rgba(74,77,82,.5);
-moz-border-radius:10px;
-webkit-border-radius:10px;
border-radius:10px;
max-width: 70%;
}
Such a task is a little much for CSS alone to handle. It isn't too hard in javascript.
It sounded like a nice little distraction so I played around a bit in jsfiddle. Perhaps this will help even though it's not pure css and uses some jquery.
http://jsfiddle.net/rSFUB/2/
Notice that I wrapped the <p> text in a div and added a line number div within that absolutely positioned. The javascript is:
$(document).ready(function () {
$(".message").each(function () {
var self = $(this);
var numbering = self.find(".lineNumbering").first();
var messageText = self.find("p").first();
var lineHeight = numbering.text("...").height();
var lines = messageText.height() / lineHeight;
var lineNumberingHtml = "";
for(var i = 1; i <= lines; i++) {
lineNumberingHtml = "" + lineNumberingHtml + i + "<br />";
}
numbering.html(lineNumberingHtml);
});
});
I tested in IE10, Chrome, and Firefox. The only difference between this code in the various versions is the padding on the .lineNumber div in order for it to line up with the text. Note this assumes that the line number div text and the paragraph is the same line-height.
I wish to do the following within div tags:
The words will be coloured differently using spans.
I will be given some text in a text box and via JavaScript I will need to dynamically update to div to show something like the above.
What is the best way to do this?
Will it involve a monospaced font?
Will it involve writing "hidden" text?
I wish to do entire paragraphs in this manner.
This might seem weird but the research I'm doing requires me present certain words from a given text with multiple colours and I think this might be a nice way of conveying this information.
Updating the text in the text box will update the following variables, and in turn I will need to convert these two variables into something like the image above.
text = "I am under the text above me and there is lots more text to come./n I am even moving onto a new line since I have more text"
color_per_word_position = {0:green, 1: red, 2: cyan, 4: yellow, 5: red, ...}
You will have to use a monospaced font for this.*
I basically see two options: 1. use whitespace 2. margins.
Option 1
Your text will look like
I•am•under•the•text•above
••am•under•••••text•above
where • denotes a space character. Pretty straight-forward in terms of CSS, since you don't have to worry about the spacing. The browser does it all for you. Example: http://jsfiddle.net/PYXdr/
*well, it may be possible with any font, using a lot of JS, but I guess it's not worth it.
Option 2
Since you probably don't want whitespace in between your spans, you may prefer this:
I•am•under•the•text•above
am•under text•above
Now, the spacing needs to be taken care of manually. Each span should get a margin-left that pushes it to the desired position. But before we can do that, we need to know the width of one character (using JS, since CSS does not provide that). Okay, pretty easy:
var el = document.createElement('pre');
el.style.display = 'inline-block';
el.innerHTML = ' ';
document.body.appendChild(el);
var width = parseFloat(getComputedStyle(el).width);
document.body.removeChild(el);
Now let's go ahead and move the spans:
span1.style.marginLeft = (2 * width) + 'px';
span2.style.marginLeft = (5 * width) + 'px';
Example: http://jsfiddle.net/JC3Sc/
Putting it all together
Now here's a basic example of how this might work:
var text = "I am under the text above me and there is lots more text to come.\nI am even moving onto a new line since I have more text"
var highlightBorders = [[2, 3, 4, 6], [6, 7]]; // YOUR TASK: implement the logic to display the following lines
var color_per_word_position = {0:'lime', 1: 'red', 2: 'cyan', 3:'orange', 4: 'yellow', 5: 'red'}
/* generate CSS */
var style = document.createElement('style');
for (var i in color_per_word_position) {
style.innerHTML += '.hl' + i + '{background:' + color_per_word_position[i] + '}';
}
document.head.appendChild(style);
/* generating the text */
text = text.split('\n');
var pre = document.createElement('pre');
text.forEach(function (line, i) {
var div = document.createElement('div');
var words = line.split(' ');
var result = [];
highlightBorders[i].forEach(function (len, j) {
var span = document.createElement('span');
span.innerHTML = words.splice(0, len).join(' ');
span.className = 'hl' + j;
if (j) {
span.style.marginLeft = width + 'px' // YOUR TASK: implement the logic
}
div.appendChild(span);
});
pre.appendChild(div);
});
document.body.appendChild(pre);
This is not a complete solution, since a) I don't really see which parts exactly you want to highlight and b) I don't want to spoil all the fun. But you get the idea.
Example: http://jsfiddle.net/tNyqL/
Using padding this is possible but also have absolute control by assigning text to a selector such as "p" for the class: fiddle http://jsfiddle.net/3NDs3/1/
.one {
width:200px;
}
.one p {
font: normal 14px Futura, sans-serif;
text-align:left;
padding-left:130px;
}
.two {
width:200px;
}
.two p {
text-align:center;
font: normal 14px Futura, sans-serif;
}
.three {
width:200px
}
.three p {
text-align:left;
font: normal 14px Futura, sans-serif;
padding-left:35px;
}
<div class="one">
<p>above me</p>
</div>
<div class="two">
<p>i am under the text above me</p>
</div>
<div class="three">
<p>under</p>
</div>
Example code:
<p class="test">string</p>
I want to change the color on the last letter, in this case "g", but I need solution with css, I don't need a javascript solution.
I display the string letter by letter and i cant use static solution.
Everyone says it can't be done. I'm here to prove otherwise.
Yes, it can be done.
Okay, so it's a horrible hack, but it can be done.
We need to use two CSS features:
Firstly, CSS provides the ability to change the direction of the flow of the text. This is typically used for scripts like Arabic or Hebrew, but it actually works for any text. If we use it for English text, the letters are displayed in reverse order to how the appear in the markup. So to get the text to show as the word "String" on a reversed element, we would have to have markup that reads "gnirtS".
Secondly, CSS has the ::first-letter pseudo-element selector, which selects the first letter in the text. (other answers already established that this is available, but there's no equivalent ::last-letter selector)
Now, if we combine the ::first-letter with the reversed text, we can select the first letter of "gnirtS", but it'll look like we're selecting the last letter of "String".
So our CSS looks like this:
div {
unicode-bidi:bidi-override;
direction:rtl;
}
div::first-letter {
color: blue;
}
and HTML:
<div>gnirtS</div>
Yes, this does work -- you can see the working fiddle here: http://jsfiddle.net/gFcA9/
But as I say, it is a bit hacky. And who wants to spend their time writing everything backwards? Not really a practical solution, but it does answer the question.
Use ::after pseudo-element combined with attr() function:
p::after {
content: attr(data-end) ;
color: red ;
}
<p data-end="g">Strin</p>
p::after {
content: attr(data-end) ;
color: red ;
}
<p data-end="g">Strin</p>
Another solution is to use ::after
.test::after{
content: "g";
color: yellow;
}
<p class="test">strin</p>
This solution allows to change the color of all characters not only letters like the answer from Spudley that uses ::first-letter. See ::first-letter specification for more information. ::first-letter applies only on letters it ignores punctuation symbols.
Moreover if you want to color more than the last character you can :
.test::after{
content: "ing";
color: yellow;
}
<p class="test">str</p>
For more information on ::after check this link.
Without using javascript, your only option is:
<p class="test">strin<span class="other-color">g</span></p>
Edit for your fiddle link:
I'm not really sure why you said you didn't need a javascript solution, since you have quite a bit of it already. Regardless, in this example, you need to make only a couple small changes. Change line 10 from
elem.text(elem.text() + contentArray[current++]);
to
if ( current == contentArray.length-1 ) {
elem.html(elem.html() + "<span style='color:red'>"+contentArray[current++]+"</span>");
} else {
elem.html(elem.html() + contentArray[current++]);
}
Note that it's important to use .html() instead of .text() now, since there's actually HTML markup being inserted.
Working fiddle: http://jsfiddle.net/QTUsb/2/
It could be achieved using only CSS and an ::after pseudo-element without any changes in HTML:
.test {
font-size: 16pt;
position: relative;
}
.test::after {
bottom: 0;
color: red;
content: 'g';
position: absolute;
transform: translate(-100%, 0);
}
<p class="test">string</p>
In what way do you "display the string letter by letter"? If you're looping through the characters in a string (variable) you can certainly tell when you're at the last letter and wrap it in a whether doing so on the server side or client side.
Looking at the fiddles attached to another of your questions ...
If this is what you're talking about, you might have to set the .innerHTML of the element instead of the element.text()
From the fiddle at http://jsfiddle.net/SLKEn/ you would change it to something like this
if(current < contentArray.length) {
elem.html(
elem.html() +
(current == contentArray.length-1 ?
'<span class="lastchar">' + contentArray[current++] + '</span>' :
contentArray[current++])
);
}
along with CSS span.lastchar { color: red; }
Update: working fiddle based on your other question.
$(document).ready(function() {
var str=$("span").text();
strArr=str.split("");
for(var key=0;key<=strArr.length-1;key++) {
if(key==strArr.length-1) {
var newEle="<span id='lastElement'>"+strArr[key]+"</div>";
strArr[key]=newEle;
}
}
var newtext=strArr.join("");
$("span").html(newtext);
});
span#lastElement {
color: red;
}
i dont have the ability to comment on an answer thread but i wanted to point out an error in an answer provided by Marc_Alx that otherwise works wonderfully. that solution worked for me only after adding a semi-colon behind the content property... so it looks like content:"ing";
.test::after{
content:"ing";
color:yellow;
}
<p class="test">str</p>