CSS last three children only if condition - css

I'm trying to learn how to select the <li> among the last three elements of a <ul> such that their (one-based) index is greater than the greatest multiple of 3 which is smaller than the number of list elements.
So for example:
if there are 9 <li> elements in <ul>, I want elements 1-6 to have font-weight:normal and elements 7,8 and 9 to have font-weight:bold.
if there are 8 <li> elements in <ul>, I want elements 1-6 to have font-weight:normal and elements 7 and 8 to have font-weight:bold.
if there are 7 <li> elements in <ul>, I want elements 1-6 to have font-weight:normal and element 7 to have font-weight:bold.
I tried this CSS selector but it seems to make everything bold:
li:nth-last-child(1n+0),
li:nth-last-child(2n+0),
li:nth-last-child(3n+0) {font-weight:bold;}
How else do I do this?

I think you want
li:nth-last-child(-n+3):nth-child(3n+1),
li:nth-last-child(-n+3):nth-child(3n+1) ~ * {
font-weight: bold;
}
That is, it selects the element among the last 3 whose index mod 3 is 1. And then it also adds the following siblings (if any).
/* Tests */
document.styleSheets[0].ownerNode.textContent += ".fail { color: red; } .fail::after { content: ' - FAIL'; }"
for (var i=0; i<10; ++i) {
var ul = document.body.appendChild(document.createElement('ul'));
for (var j=0; j<=i; ++j) {
var li = ul.appendChild(document.createElement('li'));
li.appendChild(document.createTextNode(j+1+'-th item '));
}
for (var j=0; j<=i; ++j) {
var li = ul.children[j];
var isSelected = getComputedStyle(li).fontWeight === '700';
if(isSelected !== (j >= Math.floor(i/3)*3)) li.className = "fail";
}
}
li:nth-last-child(-n+3):nth-child(3n+1),
li:nth-last-child(-n+3):nth-child(3n+1) ~ * {
font-weight: bold;
}
In case there are more than three elements, you can simplify it to
li:nth-last-child(-n+4):nth-child(3n) ~ * {
font-weight: bold;
}
That is, it gets the element(s) among the last 4 whose index is a multiple of 3. And then it selects the following siblings.
/* Tests */
document.styleSheets[0].ownerNode.textContent += ".fail { color: red; } .fail::after { content: ' - FAIL'; }"
for (var i=0; i<10; ++i) {
var ul = document.body.appendChild(document.createElement('ul'));
for (var j=0; j<=i; ++j) {
var li = ul.appendChild(document.createElement('li'));
li.appendChild(document.createTextNode(j+1+'-th item '));
}
for (var j=0; j<=i; ++j) {
var li = ul.children[j];
var isSelected = getComputedStyle(li).fontWeight === '700';
if(isSelected !== (j >= Math.floor(i/3)*3)) li.className = "fail";
}
}
li:nth-last-child(-n+4):nth-child(3n) ~ * {
font-weight:bold;
}
And if you dislike universal selectors,
li:nth-last-child(-n+3):nth-child(3n+1),
li:nth-last-child(-n+2):nth-child(3n+2),
li:nth-last-child(-n+1):nth-child(3n+3)
/* Tests */
document.styleSheets[0].ownerNode.textContent += ".fail { color: red; } .fail::after { content: ' - FAIL'; }"
for (var i=0; i<10; ++i) {
var ul = document.body.appendChild(document.createElement('ul'));
for (var j=0; j<=i; ++j) {
var li = ul.appendChild(document.createElement('li'));
li.appendChild(document.createTextNode(j+1+'-th item '));
}
for (var j=0; j<=i; ++j) {
var li = ul.children[j];
var isSelected = getComputedStyle(li).fontWeight === '700';
if(isSelected !== (j >= Math.floor(i/3)*3)) li.className = "fail";
}
}
li:nth-last-child(-n+3):nth-child(3n+1),
li:nth-last-child(-n+2):nth-child(3n+2),
li:nth-last-child(-n+1):nth-child(3n+3) {
font-weight: bold;
}

Use li:nth-last-child(-n+3)
That should give you the last 3 elements even if the list is dynamic. Whether the list has 10, 20 or 30 elements, it will always target the last 3

Rather than using n notation on :nth-last-child you can just use a number on :nth-child. Mind you, both of these solutions are technically targeting the first 6 items to override the styles that would be applied to the remaining list items.
li{
font-weight:bold;
}
li:nth-child(1),
li:nth-child(2),
li:nth-child(3),
li:nth-child(4),
li:nth-child(5),
li:nth-child(6){
font-weight:normal;
}
JSFIDDLE
Alternatively, if you wanted to use n notation you could use
li{
font-weight:bold;
}
li:nth-child(-n+6){
font-weight:normal;
}
to select the first 6 elements
JSFIDDLE
If you truly wanted to select all elements after the last 6 you would use:
li:nth-child(n+6) ~ *{
font-weight:bold;
}
JSFIDDLE

Related

Can i exclude spaces from text decoration?

Maybe my question is too simple :) Struggling to exclude &snbsp and spaces from being visualized with strike through:
del {
text-decoration: line-through;
background-color: var(--color-warn-light);
}
So in <del>&nbsp</del> the space is not visualized like a minus '-'.
Is there a possibility that CSS can be used to exclude some characters from being decorated?
Update: found text-decoration-skip: spaces by its is not supported by most browsers :(
As you and #dippas figured out, this is currently not supported via pure CSS across all browsers.
I suggest doing this with JavaScript, by splitting the text you are interested in at the space character into separate span elements. You can then apply your line-through decoration to the span elements, which will not include the spaces.
Here is a simple example:
const elements = document.querySelectorAll("del");
for (let i = 0; i < elements.length; i++) {
const elem = elements[i];
const words = elem.innerText.split(" ");
const spans = words.map((word) => {
const span = document.createElement("span");
span.innerText = word;
return span;
});
elem.innerHTML = "";
spans.forEach((span) => {
elem.appendChild(span);
elem.innerHTML += " ";
});
}
del {
text-decoration: none;
}
del span {
text-decoration: line-through;
}
<div>
<del>All the text to be marked through here</del>
<br />
<del>Additional text to be marked through here</del>
</div>
Inline Block
You can wrap the space in a span with display set to inline-block:
span {
display: inline-block;
}
<del>text<span>&nbsp</span>text</del>
Selector :not
span:not(.space) {
text-decoration: line-through;
}
<span>text</span>
<span class="space">&nbsp</span>
<span>text</span>
JavaScript
Or you can use some simple JavaScript:
const elements = document.querySelectorAll("del");
for (let i = 0; i < elements.length; i++) {
const elem = elements[i];
const words = elem.innerText.split(/\s/);
elem.innerHTML = words.join("<span> </span>")
}
span {
display: inline-block;
}
<del>text text</del>
<del>text text</del>

Automatically style each link on a page differently using nth-child/type?

I want to add a special style to specific links on my page but I don't want to add a separate class to each link that might appear on a page. I want every 8n+1 (through 8n+8) href to be a different color. So far it's not working using nth-child or nth-of-type. I assume this is because the links are in paragraphs and lists, etc., so they aren't recognized as direct or even sibling selectors, even though the parent selector I'm prefixing it with is the parent.
Here's my CSS:
#main > a:nth-of-type(8n+1) {
color: #ef9623 !important;
}
#main > a:nth-of-type(8n+2) {
color: #dab828 !important;
}
etc. I've tried it with ~ and without either one. None of them seem to work. Is it likely that this will require jquery instead of CSS?
If the links are in paragraphs, than the css selectors need to appropriate. Assuming you have this html:
<div class="wrap">
<p>foo</p>
.
.
.
</div>
To style the links you need to select like this:
div.wrap p:nth-child(8n+2) a { … }
Because the paragraphs are the children to count.
EDIT If some of the links are in paragraphs and some not, you need to create a more flexible selector. One thing you can do is to set a class for each child of the first level like:
<div class="wrap">
<p class="countable">foo</p>
<div class="countable"><a … </a></div
.
.
.
</div>
Than you can select like: div.wrap .countable:nth-child(…) a { … }
I am unsure if even: div.wrap > *:nth-child(…) a { … } could work, but I am pretty sure…
PROOF
EDIT #2
In fact the nth-child pseudo selector will only work for direct children (>), to style each 8th link, no matter where in the HTML you will need to use JS.
$(document).ready(function () {
$.each($('#main a'), function (idx, e) {
// % the nth child
if (idx % 8 == 0) {
//do something with the element
$(e).html('eighth');
}
});
});
This way each link, in appearance in the DOM, will be added to a list and styled if idx % nthChild == 0.
EDIT #3
Finally, the whole thing can be simplified to:
$(document).ready(function () {
$.each($('#main a'), function (idx, e) {
$(e).addClass('nth-' + (idx % 8));
});
});
this will add a class to each link starting from nth-0 going to nth-7 and starting again until all elements are processed.
Thanks to Philipp, this is what I ended up doing:
the js...
$.each($('#main .col-md-9 .entry-content a'), function (idx, e) {
// % the nth child
if (idx % 1 == 0 ) {
$(e).addClass('link-one');
}
if (idx % 2 == 0 ) {
$(e).addClass('link-two');
}
if (idx % 3 == 0 ) {
$(e).addClass('link-three');
}
if (idx % 4 == 0) {
$(e).addClass('link-four');
}
if (idx % 5 == 0) {
$(e).addClass('link-five');
}
if (idx % 6 == 0) {
$(e).addClass('link-six');
}
if (idx % 7 == 0) {
$(e).addClass('link-seven');
}
if (idx % 8 == 0) {
$(e).addClass('link-eight');
}
});
And the CSS...
.link-one {
color: #ef9623 !important;
}
.link-two {
color: #dab828 !important;
}
.link-three {
color: #c0d72f !important;
}
.link-four {
color: #1bbaed !important;
}
.link-five {
color: #aa84b5 !important;
}
.link-six {
color: #e80783 !important;
}
.link-seven {
color: #ef9623 !important;
}
.link-eight {
color: #dab828 !important;
}
This seems to be working perfectly. I'm very happy.

how to remove menu's border in asp.net

Hi i have a menu control in asp.net....i write below code for that...and i bind the menu itemss dynamically..
DataView viewItem = new DataView(table);
viewItem.RowFilter = "Id=" + menuItem.Value;
foreach (DataRowView childView in viewItem)
{
DataSet ds = da.GetDataSet("select top 5 Id,PageName,PageLink from Tbl_MstPageMaster where ModuleId = " + childView["Id"].ToString() + " and IsActive = 'true'");
if (ds.Tables[0].Rows.Count > 0)
{
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
MenuItem childItem = new MenuItem(ds.Tables[0].Rows[i]["PageName"].ToString(), ds.Tables[0].Rows[i]["Id"].ToString());
childItem.NavigateUrl = ds.Tables[0].Rows[i]["PageLink"].ToString();
menuItem.ChildItems.Add(childItem);
//AddChildItems(table, childItem);
}
}
}
here i need to change menu's bacKground color and remove default border...how to remove thaT...anybody suggest me..
Use this Css
#Menu ul li a,
#Menu ul li a:active {outline:none;}
So you should write CSS for it
#YourMenuID
{
background-color: red or #customcolor;
color:white;
border:0px none;
}
Where # is the menu id
And call the style sheet in your page
<link rel="stylesheet" type="text/css" src="pathofyourstylesheet"/>

css: float blocks to occupy all free space

I'm trying to make an "image mosaic" that consists mostly of images of the same size, and some of them the double height.
They all should align neatly like this:
To make automatic generation of those mosaic as easy as possible, I thought floating them would be the best option. Unfortunately, the big block causes the following ones to flow behind it, but not before:
What can I do - apart from manually positioning them - to get the images to the place I want, and still have it easy to automatically create likewise layouts?
The code I'm currently using is :
FIDDLE
HTML :
<div class="frame">
<div id="p11" class="img">1.1</div>
<div id="p12" class="img h2">1.2</div>
<div id="p13" class="img">1.3</div>
<div id="p21" class="img">2.1</div>
<div id="p22" class="img">2.2</div>
</div>
CSS :
.frame {
background-color: blue;
border: 5px solid black;
width: 670px;
}
.img {
width: 200px;
height: 125px;
background-color: white;
border: 1px solid black;
float: left;
margin: 10px;
}
.h2 {
height: 272px;
}
You need to use Javascript to achieve this effect, I had to do that once and I used http://masonry.desandro.com/ -- worked well!
Pure CSS Solution
Tested in Firefox, IE8+ (IE7 looks like it would need to be targeted to add a top margin added to 2.1 because it overlaps 1.1). See fiddle. This assumes .h2 is the middle div (as your example). If left most div it should not need any change. If right most, you would need to expand the negative margin to also include the third div following.
.h2 + div {
float: right;
margin: 10px 14px 10px 0; /*14px I believe also has to do with borders */
}
.h2 + div + div {
margin-left: -434px; /*need to account for borders*/
clear: right;
}
You can use a column layout like this:
http://jsfiddle.net/KKUZL/
I don't know if that will conflict with your automation process though....
I realize this is not a CSS-only solution, but for what it's worth (JSFiddle):
HTML:
<div id='container'></div>
CSS:
html, body {
margin:0px;
padding:0px;
height:100%;
}
body {
background-color:#def;
}
#container {
margin:0px auto;
width:635px;
min-height:100%;
background-color:#fff;
box-shadow:0px 0px 5px #888;
box-sizing:border-box;
overflow:auto;
}
.widget {
float:left;
box-sizing:border-box;
padding:10px 10px 0px 0px;
}
.widget > div{
height:100%;
box-sizing:border-box;
color:#fff;
font-size:3em;
text-align:center;
padding:.5em;
overflow:hidden;
}
.widget > div:hover {
background-color:purple !important;
}
JS:
////////////////////////////////////////
// ASSUMPTIONS
//
var TWO_COLUMN_WIDGET_COUNT = 1;
var ONE_COLUMN_WIDGET_COUNT = 15;
var NUMBER_OF_COLUMNS = 2;
////////////////////////////////////////
function rand(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var colorFactory = (function () {
var colors = [
'#CC9A17',
'#9B2C16',
'#1A8B41',
'#D97114',
'#3B9EE6'];
var index = 0;
return function () {
if (index > 4) {
index = 0;
}
return colors[index++];
}
})();
function widgetFactory(columnSpan) {
return {
'height': rand(10, 30) * 10,
'width': 100 * columnSpan / NUMBER_OF_COLUMNS,
'columnSpan': columnSpan,
'color': colorFactory()
}
}
function getWidgets() {
var widgets = [];
for (var i = 0; i < TWO_COLUMN_WIDGET_COUNT; i++) {
widgets.push(widgetFactory(2));
}
for (var i = 0; i < ONE_COLUMN_WIDGET_COUNT; i++) {
widgets.push(widgetFactory(1));
}
return widgets;
}
function getHighestOffset(offsets){
}
function getHighestSlot(offsets, numOfColumns){
}
$(document).ready(function () {
var container = $('#container');
var widgets = getWidgets();
var col1 = Math.floor(container[0].offsetLeft);
var col2 = Math.floor(container[0].clientWidth / 2 + container[0].offsetLeft);
var offsets = {};
offsets[col1] = 0;
offsets[col2] = 0;
var newLine = true;
for (var i = 0; i < widgets.length; i++) {
var w = widgets[i];
var marginTop = 0;
if (offsets[col1] < offsets[col2]) {
marginTop = (offsets[col2] - offsets[col1]) * -1;
}
if(offsets[col1] <= offsets[col2] || w.columnSpan == 2){
newLine = true;
}
var margin = 'margin-top:' + marginTop + 'px;';
var height = 'height:' + w.height + 'px;';
var color = 'background-color:' + colorFactory() + ';';
var width = 'width:' + w.width + '%;';
var padding = newLine ? "padding-left:10px;" : "";
var component = $('<div class="widget" style="' + padding + margin + height + width + '"><div style="' + color + '">' + i + '</div></div>');
component.appendTo(container);
var c = component[0];
var index = 0;
var minOffset = null;
for(var p in offsets){
if(minOffset == null || offsets[p] < minOffset){
minOffset = offsets[p];
}
if(p == Math.floor(c.offsetLeft)){
index = 1;
}
if(index > 0 && index <= w.columnSpan){
offsets[p] = c.offsetTop + c.offsetHeight;
index++;
}
}
newLine = minOffset >= offsets[col1];
}
});

IE: nth-child() using odd/even isn't working

My table (that works perfectly on Chrome, FireFox and Opera) is not displaying correctly on Internet Explorer.
The background remains white! (I am using IE-8)
CSS code:
/*My Table*/
.my_table{
border-collapse:collapse;
font:normal 14px sans-serif,tahoma,arial,verdana;
margin:5px 0;
}
.my_table th{
color:#fff;
background:#5E738A;
border:1px solid #3C5169;
text-align:center;
padding:4px 10px;
}
.my_table td{
color:#555;
border:1px solid #C1CAD4;
text-align:center;
padding:2px 5px;
}
.my_table tr:nth-child(even){
background:#E6EDF5;
}
.my_table tr:nth-child(odd){
background:#F0F5FA;
}
As a good workaround, jQuery has added this to their project and achieving this using JavaScript is acceptable:
For my CSS, I would have
.my_table tr.even{
background:#E6EDF5;
}
.my_table tr.odd{
background:#F0F5FA;
}
And I would use jQuery to do this:
$(document).ready(function() {
$(".my_table tr:nth-child(even)").addClass("even");
$(".my_table tr:nth-child(odd)").addClass("odd");
});
IE8 doesn't support the nth-child selector I'm afraid:
http://reference.sitepoint.com/css/pseudoclass-nthchild
You can use first-child and "+" to emulate nth-child, example:
tr > td:first-child + td + td + td + td + td + td + td + td {
background-color: red;
}
That select the 9th column, just like nth-child(9), and that works on IE
This is the Dojo version, it works fine:
dojo.addOnLoad(function(){
dojo.query("table tr:nth-child(odd)").addClass("odd");
dojo.query("table tr:nth-child(even)").addClass("even");
});
I made some time ago, a prude simple javascript solution for this problem:
https://gist.github.com/yckart/5652296
var nthChild = function (elem, num) {
var len = elem.length;
var ret = [];
var i = 0;
// :nth-child(num)
if (!isNaN(Number(num))) {
for (i = 0; i < len; i++) {
if (i === num - 1) return elem[i];
}
}
// :nth-child(numn+num)
if (num.indexOf('+') > 0) {
var parts = num.match(/\w/g);
for (i = parts[2] - 1; i < len; i += parts[0] << 0) {
if (elem[i]) ret.push(elem[i]);
}
}
// :nth-child(odd)
if (num === 'odd') {
for (i = 0; i < len; i += 2) {
ret.push(elem[i]);
}
}
// :nth-child(even)
if (num === 'even') {
for (i = 1; i < len; i += 2) {
ret.push(elem[i]);
}
}
return ret;
};
The usage is quite simple and similar to the css-selector:
var rows = document.querySelectorAll('li');
var num = nthChild(rows, 2);
var formula = nthChild(rows, '3n+1');
var even = nthChild(rows, 'even');
var odd = nthChild(rows, 'odd');
// Note, forEach needs to be polyfilled for oldIE
even.forEach(function (li) {
li.className += ' even';
});
odd.forEach(function (li) {
li.className += 'odd';
});
formula.forEach(function (li) {
li.className += ' formula';
});
num.style.backgroundColor = 'black';
http://jsfiddle.net/ARTsinn/s3KLz/

Resources