Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Group elements with CSS

Tags:

html

css

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.

like image 927
Mia Avatar asked Nov 12 '14 07:11

Mia


People also ask

How grouping elements can be used with 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.

Can elements have multiple classes CSS?

HTML elements can be assigned multiple classes by listing the classes in the class attribute, with a blank space to separate them.

How do you group items together in HTML?

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.


3 Answers

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>';
}
like image 199
Paul Avatar answered Oct 17 '22 02:10

Paul


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

like image 2
JimmyRare Avatar answered Oct 17 '22 02:10

JimmyRare


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>
like image 2
Danield Avatar answered Oct 17 '22 04:10

Danield