I made a quick template to explain what I am trying to achieve: http://codepen.io/anon/pen/XJWrjO
As you can see, there is two classes ofelements. .one
and .two
I want to group the following elements with each other via css. This will be a visual grouping; not a structural grouping.
Shortly, what I want to do is, to give margin-top
to the first element for each class cluster, and margin-bottom
to the last element of each cluster.
So, depending on my example here are the clusters:
1,2,3,4 - red cluster
5,6,7 - cyan cluster
8,9 - red cluster
10,11,12,13,14 - cyan cluster
15 - red cluster
16,17 - cyan cluster
So according to this structure, for instance, div5 would have a margin-top
and div7 would have a margin-bottom
.
Or, div5 would have a margin-top
and div8 would have a margin-top
(similar result with the previous statement)
Any kind of solution that allows visual grouping of the similar classed items that follow each other, is accepted.
No JS, only CSS.
The CSS Grouping Selector The grouping selector selects all the HTML elements with the same style definitions. It will be better to group the selectors, to minimize the code. To group selectors, separate each selector with a comma.
HTML elements can be assigned multiple classes by listing the classes in the class attribute, with a blank space to separate them.
The <div> tag is used to group other HTML content together. The <div> element doesn't add or change the content of your HTML. Instead, its main purpose is to provide an easy way to target and each group.
Since you can't combine :last-child
with .class
selector, it's hard to assign margin-bottom
to the last element of a cluster. But you can detect the switch to another cluster by using +
:
.one + .two, .two + .one {
margin-top: 50px;
}
See the DEMO.
EDIT regarding comment asking for a general rule:
There's not a general rule like this I am aware of which would work right now, since CSS doesn't provide anything like :nth-of-class
nor does it support back references to classes of previous selectors. So you can't do anything like
.{class-variable} + :not(.{class-variable})
but if you have a list of all possible classes, you could do something similar:
.one + :not(.one),
.two + :not(.two) {
margin-top: 50px;
}
You would need to repeat that for every class that is in the list. See DEMO 2 which has three different classes.
When generating the output, you would need to collect all classes in an array and could create an additional style element in your output to avoid to adapt your CSS every time. In PHP, this could look like
$style = '';
foreach ($classes AS $class) {
$style .= '.' . $class . ' + :not(.' . $class . '), ';
}
if ($style != '') {
$output = '<style>' . substr($style, 0, -2) . ' { margin-top: 50px; }</style>';
}
Just to show an alternative, you could order your clusters in the markup by assigning a data-cluster
attribute:
<div class="two" data-cluster="red">6</div>
And then style it as you wish:
div[data-cluster="red"] {
background: red;
margin-top: 10px;
}
div[data-cluster="red"] + div[data-cluster="red"] {
margin-top: 0;
}
Demo
Just to supplement @Paul 's (excellent) answer, you could approach this problem the other way around by applying the top margin on all child elements, then override that margin when a child element is following by a child with the same class.
Like this:
div {
width: 100%;
margin: 2px;
margin-top: 50px;
}
.one + .one, .two + .two {
margin-top: 0;
}
UPDATED CODEPEN
One advantage of this approach is that the :not
selector - which isn't supported by older browsers such as ie8 - isn't necessary.
Here's an example with 3 classes
div {
width: 100%;
margin: 2px;
margin-top: 50px;
}
.one + .one, .two + .two, .three + .three {
margin-top: 0;
}
CODEPEN 2
body {
padding: 64px;
margin: 0;
text-align: center;
font-size: 20px;
font-family: Arial;
line-height: 40px;
}
div {
width: 100%;
margin: 2px;
margin-top: 50px;
}
.one + .one,
.two + .two,
.three + .three {
margin-top: 0;
}
.one {
background-color: tomato;
}
.two {
background-color: aqua;
}
.three {
background-color: maroon;
}
<div class="one">1</div>
<div class="one">2</div>
<div class="three">3</div>
<div class="three">4</div>
<div class="two">5</div>
<div class="two">6</div>
<div class="two">7</div>
<div class="one">8</div>
<div class="one">9</div>
<div class="two">10</div>
<div class="two">11</div>
<div class="three">12</div>
<div class="three">13</div>
<div class="two">14</div>
<div class="one">15</div>
<div class="two">16</div>
<div class="two">17</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