I have the following structure:
<div class="elementWrapper">
<div>1. Element</div>
<div>2. Element</div>
<div>3. Element</div>
<div class="alternate">1. Element with spec. Class</div>
<div class="alternate">2. Element with spec. Class</div>
<div class="alternate">3. Element with spec. Class</div>
<div class="alternate">4. Element with spec. Class</div>
<div class="alternate">5. Element with spec. Class</div>
<div>9. Element</div>
<div>10. Element</div>
<div>11. Element</div>
</div>
There can be a unknown number of multiple elements before and after, and I have no possibility to add a "wrapping" div around the elements with the class="alternate". (where everything would be fine).
I would like to give the first .alternate Element a border top, the last .alternate Element a border bottom. And all .alternate elements should have a different background color for each row (even/odd).
I've tried it in different ways, and I know that nth-of-type and nth-child won't work, because there is no wrapping div around my .alternate elements, and so it can't work because all Elements are counted for even/odd and so on.
So I made a pen with the problem and possible Solutions:
http://codepen.io/emjay/pen/RpyyOo
I would like to ask you, what the best way could be -without changing the structure-. Is there a working css only solution?
Thanks for your help!
Definition and Usage. The :nth-child(n) selector matches every element that is the nth child of its parent. n can be a number, a keyword (odd or even), or a formula (like an + b). Tip: Look at the :nth-of-type() selector to select the element that is the nth child, of the same type (tag name), of its parent.
The :nth-child selector allows you to select one or more elements based on their source order, according to a formula. It is defined in the CSS Selectors Level 3 spec as a “structural pseudo-class”, meaning it is used to style content based on its relationship with parent and sibling elements.
The CSS child selector has two selectors separated by a > symbol. The first selector indicates the parent element. The second selector indicates the child element CSS will style.
For the first question (adding border-top
to the first .alternate
element and border-bottom
to the last .alternate
element), you can achieve this by adding border-top
alone to:
.alternate
element that immediately follows an element that does :not()
have the .alternate
class, and,.alternate
class that immediately follows an element that does.In the case that there are no elements before the first .alternate
element, you will also need to add border-top
to the .alternate
element that is also the :first-child
and, in the case that there are no elements after the last .alternate
, you will need to add border-bottom
to the .alternate
element that is also the :last-child
.
For the second question on "zebra striping" the .alternate
elements, assuming it's irrelevant whether the odd or even elements have the alternate background
, you can achieve that with a simple :nth-of-type()
(or :nth-child()
) pseudo-class. However, if you require the first .alternate
element to always have the same background
regardless of the number of elements that precede it, you will need to resort to JavaScript - it is possible with CSS alone but requires a ridiculous number of selectors (see this answer as an example).
(function(){
var wrappers=document.querySelectorAll(".elementWrapper"),
x=wrappers.length,
divs,y,alt;
while(x--){
divs=wrappers[x].querySelectorAll(".alternate");
y=divs.length;
alt=!(y%2);
while(y--)
divs[y].classList.add((alt=!alt)?"odd":"even");
}
})();
/** JQuery **/
//$('.alternate:odd').addClass('odd')
//$('.alternate:even').addClass('even');
.elementWrapper>div:not(.alternate)+div.alternate,
.elementWrapper>div.alternate+div:not(.alternate),
.elementWrapper>div.alternate:first-child{
border-top:1px solid #000;
}
.elementWrapper>div.alternate:last-child{
border-bottom:1px solid #000;
}
.elementWrapper>div.alternate.odd{
background:#ccc;
}
.elementWrapper>div.alternate.even{
background:#eee;
}
/** Uncomment below for CSS-only zebra-striping **/
/*.elementWrapper>div.alternate:nth-of-type(odd){
background:#ccc;
}
.elementWrapper>div.alternate:nth-of-type(even){
background:#eee;
}*/
/** "housekeeping" **/.elementWrapper{background:#fff;color:#000;margin:0 0 20px;}.elementWrapper>div{font-family:sans-serif;font-size:14px;overflow:hidden;padding:5px;text-overflow:ellipsis;white-space:nowrap;}
<div class="elementWrapper">
<div>1. Element</div>
<div class="alternate">1. Element with spec. Class</div>
<div class="alternate">2. Element with spec. Class</div>
<div class="alternate">3. Element with spec. Class</div>
<div class="alternate">4. Element with spec. Class</div>
<div class="alternate">5. Element with spec. Class</div>
<div>9. Element</div>
</div>
<div class="elementWrapper">
<div>1. Element</div>
<div>2. Element</div>
<div class="alternate">1. Element with spec. Class</div>
<div class="alternate">2. Element with spec. Class</div>
<div class="alternate">3. Element with spec. Class</div>
<div class="alternate">4. Element with spec. Class</div>
</div>
Building on @Shaggy's answer, using :not
& nth-of-type
selectors, you can render what is required in pure css.
Refer code:
.elementWrapper div:not(.alternate)+div.alternate,
.elementWrapper div.alternate+div:not(.alternate) {
border-top: 2px solid blue;
}
.elementWrapper div.alternate:nth-of-type(odd) {
background: green;
}
.elementWrapper div.alternate:nth-of-type(even) {
background: red;
}
<div class="elementWrapper">
<div>1. Element</div>
<div>2. Element</div>
<div>3. Element</div>
<div class="alternate">1. Element with spec. Class</div>
<div class="alternate">2. Element with spec. Class</div>
<div class="alternate">3. Element with spec. Class</div>
<div class="alternate">4. Element with spec. Class</div>
<div class="alternate">5. Element with spec. Class</div>
<div>9. Element</div>
<div>10. Element</div>
<div>11. Element</div>
</div>
As pointed out by the OP, if there are no div
prior or after .alternate
elements, the above solution won't work. The usage of first-child
and last-child
would be preferred then.
/* if there are no elements before .alternate */
.elementWrapper > div.alternate:first-child{
border-top: 2px solid blue;
}
/* if there are no elements after .alternate */
.elementWrapper > div.alternate:last-child{
border-bottom: 2px solid blue;
}
If your .alternate elements concentrate in one region (that is , they are all together) you can get the zebra styling with these styles:
.alternate {
background: gray;
}
div:nth-of-type(odd):not(.alternate)+div.alternate~div.alternate:nth-of-type(even),
div:nth-of-type(odd):not(.alternate)+.alternate:nth-of-type(even),
div:nth-of-type(even):not(.alternate)+div.alternate~div.alternate:nth-of-type(odd),
div:nth-of-type(even):not(.alternate)+.alternate:nth-of-type(odd) {
background: red;
}
<div class="wrap">
<div class="col">
<div class="elementWrapper">
<div>1. Element</div>
<div>2. Element</div>
<div>3. Element</div>
<div class="alternate">1. Element with spec. Class</div>
<div class="alternate">2. Element with spec. Class</div>
<div class="alternate">3. Element with spec. Class</div>
<div class="alternate">4. Element with spec. Class</div>
<div class="alternate">5. Element with spec. Class</div>
<div>9. Element</div>
<div>10. Element</div>
<div>11. Element</div>
</div>
</div>
<div class="col">
<div class="elementWrapper">
<div>1. Element</div>
<div>2. Element</div>
<div>3. Element</div>
<div>4. Element</div>
<div class="alternate">1. Element with spec. Class</div>
<div class="alternate">2. Element with spec. Class</div>
<div class="alternate">3. Element with spec. Class</div>
<div class="alternate">4. Element with spec. Class</div>
<div class="alternate">5. Element with spec. Class</div>
<div>10. Element</div>
<div>11. Element</div>
<div>12. Element</div>
</div>
</div>
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With