I have say 3 spans as below :
<span class = "testVar1" onClick = "testFunction(Var1)">
<span class = "testVar2" onClick = "testFunction(Var2)">
<span class = "testVar3" onClick = "testFunction(Var3)">
testFunction(var){
here I assign class "on" to the span which calls this function
}
If span with class testVar1 calls this then it becomes
<span class = "testVar1 on" onClick = "testFunction(Var1)"></span>
My Css is as below
.test .on {
some CSS
}
Is there a way in CSS where I can use a variable and apply css to those span which is clicked?
Like
.test[Var1 or Var2 or Var3] .on {
some CSS
}
I have achieved it by using multiple selectors manually like#
.testVar1 .on {
some CSS
}
.testVar2 .on {
some CSS
}
I have read the post Using regular expression in css? , it,s helpful but not answering my question.
In this post css is applied to all the element, but I want css to be applied only to the element which called the function.
and so on.
Any help or pointers would be appreciated!
Thanks!
You are making things too complicated. Just use the same CSS class on all of them, then add the click listener programmatically, not as an inline onlick listener:
document.querySelectorAll('span.test').forEach(
span =>
span.addEventListener('click', () => {
console.log(`you clicked ${span.innerText}`)
span.classList.toggle('on')
})
)
.test {
background: red;
color: white;
display: inline-block;
padding: 40px;
}
.test.on {
background: green;
}
<span class="test">foo</span>
<span class="test">bar</span>
<span class="test">baz</span>
If you insist on inline event listeners (you really shouldn't, it's widely considered bad practice), for this simple example it's probably even easier:
function foobar(span) {
console.log(`you clicked ${span.innerText}`)
span.classList.toggle('on')
}
.test {
background: red;
color: white;
display: inline-block;
padding: 40px;
}
.test.on {
background: green;
}
<span class="test" onclick="foobar(this)">foo</span>
<span class="test" onclick="foobar(this)">bar</span>
<span class="test" onclick="foobar(this)">baz</span>
You can use regex selector: span[class^='test'] which means select every span with class start with "test".
You can combine it with another class (.on) like that: span[class^='test'].on
As for inline code, you can do something like that:
const spans = document.querySelectorAll('span[class^="test"]'); // select all spans
for (var i=0; i < spans.length; i++) { // iterate them
spans[i].addEventListener('click',function() { // add event listener to them
this.classList.add('on'); // set class on click
});
}
span[class^='test'] {color: blue;}
span[class^='test'].on { color: red; }
<span class="testVar1">1</span>
<span class="testVar2">2</span>
<span class="testVar3">3</span>
Check this for selecting element with more then one class.
And this for regExp selector.
Enjoy code!
I'm using LESS in one of my projects right now and I need to create some colour-schemes for different users. I'm building a portal and based on what kind of user logs in, the colour-scheme needs to change.
So in my mixins.less (which I can't modify) file I have:
#color-button-bg: #333;
#color-button-txt: #fff;
#color-button-fs: 1.5rem;
#color-button-fw: 500;
#color-button-hover-pct: 10%;
.base-btn-default(#type: button) {
background: ~"#{color-button-bg}";
border: 1px solid ~"#{color-button-bg}";
color: ~"#{color-button-txt}";
font-size: ~"#{color-button-fs}";
font-weight: ~"#{color-button-fw}";
&:hover, &:focus {
#color-btn-hover: ~"color-button-bg";
#color-btn-hover-pct: ~"color-button-hover-pct";
background: darken(##color-btn-hover,##color-btn-hover-pct);
border-color: darken(##color-btn-hover,##color-btn-hover-pct);
color: ~"#{color-button-txt}";
}
}
And in a separate file with client-specific mixins I tried the following:
/* Override default color with theme-color */
.theme-styling() {
#color-button-bg: #main-theme-color;
}
Then finally I wanted to add a class to my <body> tag and style the colour-scheme based on that classname:
body.theme-a {
#main-theme-color: teal;
.theme-styling();
}
However, this doesn't seem to work. I think it has something to do with scoping / Lazy evaluation, but I'm not that experienced in LESS yet, to see where my error is.
I created a Codepen for it, without the separate files and in a bit of a simplified form:
https://codepen.io/jewwy0211/pen/JVNZPv
I've just played around with your codepen a bit. When you define the variable in your mixin, it does work, the problem is that you then don't use that variable in the mixin or in the class that contains the mixin.
So, if you've got 2 buttons like this:
<div class="wrapper one">
<button>Theme 1</button>
</div>
<div class="wrapper two">
<button>Theme 2</button>
</div>
You can call their theme-specific variable mixins in their respective classes to get the vars set, but you then must use the vars within the same class:
.wrapper.one {
.theme-styling-1();
background-color: #color-button-bg;
}
.wrapper.two {
.theme-styling-2();
background-color: #color-button-bg;
}
/* Theme Vars */
.theme-styling-1() {
#color-button-bg: teal;
}
.theme-styling-2() {
#color-button-bg: red;
}
EDIT: Here's a codepen: https://codepen.io/mmshr/pen/OGZEPy
I have a scenario to change the branding color and few other styling variables on the portal at run time based on some conditions. I'm able to achieve that
using CSS (look at the below sample snippet).
But since all our CSS are generated by converting the LESS files at compile time, not sure on how to write a similar logic in LESS so that it generates the CSS like below?
:root {
--brand-color: yellow;
}
h1 {
color: var(--brand-color);
}
<h1 id="demo">Hello</h1>
<button onclick="myFunction()">Click me</button>
function myFunction() {
document.documentElement.style.setProperty('--brand-color', 'red');
}
#yellow-color: yellow;
#red-color: red;
h1{
color: #yellow-color;
&.red-color{
color: #red-color;
}
}
Add class instead
function myFunction(){
$("myelement").addClass("red-color");
}
Line 3 is a hidden <div> . I don't want that one to be taken from the odd/even css rule.
What is the best approach to get this to work?
.hidden {display:none;}
.box:not(.hidden):nth-child(odd) { background: orange; }
.box:not(.hidden):nth-child(even) { background: green; }
<div class="wrap">
<div class="box">1</div>
<div class="box">2</div>
<div class="box hidden">3</div>
<div class="box">4</div>
<div class="box">5</div>
<div class="box">6</div>
<div class="box">7</div>
</div>
http://jsfiddle.net/k0wzoweh/
Note: There can be multiple hidden elements.
:nth-child() pseudo-class looks through the children tree of the parent to match the valid child (odd, even, etc), therefore when you combine it with :not(.hidden) it won't filter the elements properly.
Alternatively, we could fake the effect by CSS gradient as follows:
.hidden {display:none;}
.wrap {
line-height: 1.2em;
background-color: orange;
background-image: linear-gradient(transparent 50%, green 50%);
background-size: 100% 2.4em;
}
<div class="wrap">
<div class="box">xx</div>
<div class="box">xx</div>
<div class="box hidden">xx</div>
<div class="box">xx</div>
<div class="box">xx</div>
<div class="box">xx</div>
<div class="box">xx</div>
</div>
Pseudo-selectors don't stack, so your :not doesn't affect the :nth-child (nor would it affect :nth-of-type etc.
If you can resort to jQuery, you can use the :visible pseudo-selector there, although that's not a part of the CSS spec.
If you're generating the HTML and can change that, you can apply odd/even with logic at run-time, eg in PHP:
foreach ($divs AS $i => $div) {
echo '<div class="box ' . ($i % 2 ? 'even' : 'odd') . '">x</div>';
}
Even trying to do something tricky like
.box[class='box']:nth-of-type(even)
doesn't work, because the psuedo-selector doesn't even stack onto the attribute selector.
I'm not sure there's any way to do this purely with CSS - I can't think of any right now.
Here's a CSS-only solution:
.box {
background: orange;
}
.box:nth-child(even) {
background: green;
}
.box.hidden {
display: none;
}
.box.hidden ~ .box:nth-child(odd) {
background: green;
}
.box.hidden ~ .box:nth-child(even) {
background: orange;
}
<div class="wrap">
<div class="box">xx</div>
<div class="box">xx</div>
<div class="box hidden">xx</div>
<div class="box">xx</div>
<div class="box">xx</div>
<div class="box">xx</div>
<div class="box">xx</div>
</div>
Since my rows are being hidden with js, I found that the easiest approach for me was to just add an additional hidden row after each real row that I hide, and remove the hidden rows when I show the real rows again.
Hide the rows you want to hide calling .hide() for each table row, then call
$("tr:visible:even").css( "background-color", "" ); // clear attribute for all rows
$("tr:visible:even").css( "background-color", "#ddddff" ); // set attribute for even rows
Add your table name to the selector to be more specific. Using :even makes it skip the Header row.
As #Fateh Khalsa pointed out, I had a similar problem and since I was manipulating my table with JavaScript (jQuery to be precise), I was able to do the following:
(Note: This assumes use of JavaScript/jQuery which the OP did not state whether or not would be available to them. This answer assumes yes, it would be, and that we may want to toggle visibility of hidden rows at some point.)
Inactive records (identified with the CSS class "hideme") are currently visible.
Visitor clicks link to hide inactive records from the list.
jQuery adds "hidden" CSS class to "hideme" records.
jQuery adds additional empty row to the table immediately following the row we just hid, adding CSS classes "hidden" (so it doesn't show) and "skiprowcolor" so we can easily identify these extra rows.
This process is then reversed when the link is clicked again.
Inactive records (identified with the CSS class "hideme") are currently hidden.
Visitor clicks link to show inactive records from the list.
jQuery removes "hidden" CSS class to "hideme" records.
jQuery removes additional empty row to the table immediately following the row we just showed, identified by CSS class "skiprowcolor".
Here's the JavaScript (jQuery) to do this:
// Inactive Row Toggle
$('.toginactive').click(function(e) {
e.preventDefault();
if ($(this).hasClass('on')) {
$(this).removeClass('on'); // Track that we're no longer hiding rows
$('.wrap tr.hideme').removeClass('hidden'); // Remove hidden class from inactive rows
$('.wrap tr.skiprowcolor').remove(); // Remove extra rows added to fix coloring
} else {
$(this).addClass('on'); // Track that we're hiding rows
$('.wrap tr.hideme').addClass('hidden'); // Add hidden class from inactive rows
$('.wrap tr.hideme').after('<tr class="hidden skiprowcolor"></tr>');
// Add extra row after each hidden row to fix coloring
}
});
The HTML link is simple
Hide/Show Hidden Rows
scss for #tim answer's above, to keep class name changes to a minimum
$selector: "box";
$hidden-selector: "hidden";
.#{$selector} {
background: orange;
:nth-child(even) {
background: green;
}
&.#{$hidden-selector} {
display: none;
}
&.#{$hidden-selector} ~ {
.#{$selector} {
&:nth-of-type(odd) {
background: green;
}
&:nth-of-type(even) {
background: orange;
}
}
}
}
Another way, albeit on the fringe side, is to have an extra <tbody> and either move or copy rows there. Or, an extra div wrapper if using OPs example. Copying easiest of course in regards to restoring etc.
This approach can be useful in some cases.
Below is a simple example where rows are moved when filtered. And yes, it is ranking of stripper names, found it fitting as we are talking stripes ... hah
const Filter = {
table: null,
last: {
tt: null,
value: ''
},
name: function (txt) {
let tb_d = Filter.table.querySelector('.data'),
tb_f = Filter.table.querySelector('.filtered'),
tr = tb_d.querySelectorAll('TR'),
f = 0
;
tb_f.innerHTML = '';
if (txt.trim() == '') {
tb_d.classList.remove('hide');
} else {
txt = txt.toLowerCase();
for (let i = 0; i < tr.length; ++i) {
let td = tr[i].querySelectorAll('TD')[1];
if (td.textContent.toLowerCase().includes(txt)) {
tb_f.appendChild(tr[i].cloneNode(true));
f = 1;
}
}
if (f)
tb_d.classList[f ? 'add' : 'remove']('hide');
}
},
key: function (e) {
const v = e.target.value;
if (v == Filter.last.value)
return;
Filter.last.value = v;
clearTimeout(Filter.last.tt);
Filter.last.tt = setTimeout(function () { Filter.name(v); }, 200);
}
};
Filter.table = document.getElementById('table');
Filter.table.addEventListener('keyup', Filter.key);
table {
width: 200px;
border: 3px solid #aaa;
}
tbody tr { background: #e33; }
tbody tr:nth-child(even) { background: #e3e; }
.hide { display: none; }
<table id="table">
<thead>
<tr><th></th><th><input type="text" id="filter" data-keyup="filter" /></th></tr>
<tr><th>#</th><th>Name</th></tr>
</thead>
<tbody class="filtered">
</tbody>
<tbody class="data">
<tr><td>1</td><td>Crystal</td></tr>
<tr><td>2</td><td>Tiffany</td></tr>
<tr><td>3</td><td>Amber</td></tr>
<tr><td>4</td><td>Brandi</td></tr>
<tr><td>5</td><td>Lola</td></tr>
<tr><td>6</td><td>Angel</td></tr>
<tr><td>7</td><td>Ginger</td></tr>
<tr><td>8</td><td>Candy</td></tr>
</tbody>
</table>
You can use another type of CSS selector: tbody > tr:nth-of-type(odd)
to only target tr nodes, and then, instead of using class names to hide the rows, simply wrap them with some element (which hides them), so the CSS selector would only match odd table rows:
const searchElem = document.querySelector('input');
const tableElem = document.querySelector('table');
const tableBody = document.querySelector('tbody');
function search() {
const str = searchElem.value.toLowerCase();
const rows = tableElem.querySelectorAll('tr');
// remove previous wrappers
// https://stackoverflow.com/a/48573634/104380
tableBody.querySelectorAll('div').forEach(w => {
w.replaceWith(...w.childNodes)
});
// create a wrapper which hides its content:
const wrapper = document.createElement("div");
wrapper.setAttribute('hidden', true);
rows.forEach(function(row){
const text = row.textContent.toLowerCase();
if (str.length && !text.includes(str)) {
// replace row with wrapper and put the row inside it
row.replaceWith(wrapper);
wrapper.appendChild(row);
}
});
}
searchElem.addEventListener('keyup', search);
tbody > tr:nth-of-type(odd) {
background: pink
}
<input type="search" placeholder="search">
<table>
<tbody>
<tr><td>Apple<td>220
<tr><td>Watermelon<td>465
<tr><td>Orange<td>94
<tr><td>Pear<td>567
<tr><td>Cherry<td>483
<tr><td>Strawberry<td>246
<tr><td>Nectarine<td>558
<tr><td>Grape<td>535
<tr><td>Mango<td>450
<tr><td>Blueberry<td>911
<tr><td>Pomegranate<td>386
<tr><td>Carambola<td>351
<tr><td>Plum<td>607
<tr><td>Banana<td>292
<tr><td>Raspberry<td>912
<tr><td>Mandarin<td>456
<tr><td>Jackfruit<td>976
<tr><td>Papaya<td>200
<tr><td>Kiwi<td>217
<tr><td>Pineapple<td>710
<tr><td>Lime<td>983
<tr><td>Lemon<td>960
<tr><td>Apricot<td>647
<tr><td>Grapefruit<td>861
<tr><td>Melon<td>226
<tr><td>Coconut<td>868
<tr><td>Avocado<td>385
<tr><td>Peach<td>419
</tbody>
</table>
How to make conditions in a CSS stylesheet?
Here I got a stylesheet.. But if the div.menu_active is added on an element the class has to behave like its hovered? How can you do that?
Or is there an even better way to contruct the stylesheet for this solution?
<div class="menu">menu</div>
<div class="menu menu_active">menu</div> // has to behave like menu:hover
<div class="menu_green">menu</div>
<div class="menu_green menu_active">menu</div> // has to behave like menu_green:hover
div.menu {
background:url('menu_opacity50.png');
}
div.menu_green {
background:url('menu_green_opacity50.png');
}
div.menu_active {
}
div.menu:hover {
background:url('menu_opacity100.png');
}
div.menu_green:hover {
background:url('menu_green_opacity100.png');
}
If I understand correctly, this is what you need:
div.menu:hover, .menu.menu_active {
background:url('menu_opacity100.png');
}
div.menu_green:hover, .menu_green.menu_active {
background:url('menu_green_opacity100.png');
}
.menu.menu_active will select elements that have both of the listed classes, such as <div class="menu menu_active">.
I think you might mean this:
div.menu.menu_active,
div.menu:hover {
background:url('menu_opacity100.png');
}
div.menu_green.menu_active,
div.menu_green:hover {
background:url('menu_green_opacity100.png');
}
You might want to do this
div.menu {
background:url('menu_opacity50.png');
}
div.menu_green {
background:url('menu_green_opacity50.png');
}
div.menu.menu_active {
background:url('menu_opacity100.png');
}
div.menu_green.menu_active {
background:url('menu_green_opacity100.png');
}
Overlay the hover element exactly over normal state and hide it (display:none) then use JS/jQuery to toggle the display.