Group elements with CSS - html

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.

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>

check it may be it helps you, what you achive :-
Demo
div:nth-child(1){margin-top:10px;color:green}
div:nth-child(17){margin-bottom:10px;color:yellow}

Is this what you are trying to achieve?
Check demo.
CSS:
.one-group div:last-child{
margin-bottom:15px;}
.two-group div:last-child{
margin-bottom:15px;}

Related

Highlight current navigation tab based on url or subdirectory

I've created a vertical navigation on the left of our site. We'd like the background color for a .item to change based on the subdirectory where a user is viewing content. So if someone clicks on a nav .item, the href will redirect them to a page and we want that .item to be highlighted a unique hex color that we can customize for each nav .item. All 6 nav items would have a different color.
One point of clarification is that sometimes folks may visit our site without having ever clicked a navigation item. I want the navigation items to still be highlighted based on the current subdirectory where a person is viewing content. This helps them easily identify where they are and how to get back if they navigate to other parts of the community. Also if a person does a global search and stumbles upon content in one of our 6 main areas, we want the nav menu to instantly identify their current location (based on url) and highlight that nav .item in our vertical nav bar.
Is Javascript or Jquery the way to go? Any help would be appreciated!!
Heres a FIDDLE with all the code.
sample CSS:
.navback {
position: fixed;
top: 0;
left: 0px;
width: 100px;
height: 100%;
background: #283237;
z-index: 4;
}
.navbar {
position: fixed;
top: 44px;
left: 0px;
width: 100px;
height: 60vh;
background: #283237;
display: flex;
z-index: 5;
flex-direction: column;
}
.topbar {
border-top: 1px solid #000;
top: 44px;
}
.navbar .item {
flex: 1;
text-align: center;
display: flex;
justify-content: center;
flex-direction: column;
padding-top: 40px;
padding-bottom: 40px;
max-height: 100px;
z-index: 5;
}
.navbar .item div.label {
color: #fff;
position: relative;
top: 5px;
font-size: 13px;
font-family: -apple-system, BlinkMacSystemFont, Helvetica, Arial, "Segoe UI", sans-serif;
transition: all 300ms cubic-bezier(0.68, -0.55, 0.27, 1.55);
left: -100px;
}
Sample HTML:
<div class="topbar"></div>
<div class="navback leftnav">
<div class="navbar">
<div class="item hvr-shrink">
<a href="https://community.canopytax.com/">
<div>
<img src="https://png.icons8.com/ios/35/ffffff/home.png"/>
<div class="label">Home</div>
</div>
</a>
</div>
<div class="item hvr-shrink">
<a href="https://community.canopytax.com/community-central/">
<div>
<img src="https://png.icons8.com/ios/40/ffffff/conference-call.png">
<div class="label">Central</div>
</div>
</a>
</div>
JS/jQuery
// get the first directory by splitting "/dir/path/name" into an array on '/'
// get [1] instead of [0] b/c the first should be blank. wrap in /s.
hereDir = "/" + window.location.pathname.split("/")[1] + "/";
// rebuild the URL since you're using absolute URLs (otherwise just use hereDir)
hereUrl = window.location.protocol + "//" + window.location.host + hereDir;
$(".item")
.find("[href^='" + hereUrl + "']")
.closest(".item").addClass("here");
Note .find("[href^=...]") selects things that start with what you're looking for.
CSS
/* now use .here to style */
.item.here {
background-color: purple;
}
.item.here .label {
font-weight: bold;
}
To answer your question directly, yes this could be done also via JavaScript/jQuery but there is a far simpler way using the css :active selector.
For example, if the user clicks the .item
then the code would be:
.item:active {
background-color: #cecece; // or whatever styling you want
}
Sidenote: As a webdesigner myself, in general i'd advise using the :hover selector when it comes to navbar highlightng instead of the :active one.
Use jquery in your html (https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js)
Add the following script
$('.item').click(function(){
$('.item.active').removeClass("active");
$(this).addClass('active');
})
CSS
.item.active {
background-color: red;
}
Please see updated fiddle
If you are using jQuery you can loop through each anchor and test it against the current URL of the page like this:
$(function highlightCurrentUrl() {
var currentUrl = window.location.href;
var items = $(".item").each(function() {
var anchor = $(this).find('a');
$(this).removeClass('active');
//comparison logic
if (anchor.prop('href') == currentUrl) {
$(this).addClass("active");
}
});
});
What this does is add a class to the matching .item in the menu. (This won't work in JSFiddle due to Content Security policy so you will have to test it your own environment.)
Next, you will need to define the styles that will be applied to an .item.active DIV tag. And, if you want different colors for different items, you should probably give them ID's in you markup, so you can reference them individually:
<div class="item hvr-shrink" id="home-link">
<a href="https://community.canopytax.com/">
<div>
<img src="https://png.icons8.com/ios/35/ffffff/home.png"/>
<div class="label">Home</div>
</div>
</a>
</div>
<div class="item hvr-shrink" id="central-link">
<a href="https://community.canopytax.com/community-central/">
<div>
<img src="https://png.icons8.com/ios/40/ffffff/conference-call.png">
<div class="label">Central</div>
</div>
</a>
</div>
These rules are saying that when the active class is added to the div with the ID home-link or central-link it should have the following properties
#home-link.active {
background-color: blue;
}
#central-link.active {
background-color: green;
}

meaning and role of [class*=] css class selector

Asking here since I can't pass a proper search query with that.
Here's a code sample:
[class*="button_type"].state_2,
[class*="button_type"]:not(.state_2):hover{
background-color:#fff;
}
Furthermore what would be the use of the :not suffix?
I cannot understand why it isn't just:
.button_type.state_2,
.button_type:hover { etc..}
[class*="button_type"] is CSS class Selector (equivalent to CSS attribute selector) means that will select all elements whose class contains at least one substring "button_type".
take a look at this example:
[class*="button_type"] {
background: red;
width: 50px;
height: 50px;
display: inline-block
}
<div class="button_type"></div>
<span class="one_button_type"></span>
<article class="button_type_final"></article>
Regarding the :not() that means it will select everything but that selector which is inside the :not()
Take a look at this example:
[class*="button_type"] {
background: red;
width: 50px;
height: 50px;
display: inline-block
}
[class*="button_type"]:not(.state_2) {
border: black solid
}
<div class="button_type state_1"></div>
<span class="one_button_type state_2"></span>
<article class="button_type_final state_3"></article>

Using CSS :not with concatenated classes (.row.heading)

I'm trying to style all div elements except those in two different class groups. Everything I've tried doesn't seem to work.
The below test code should make the div with "test" text content be orange, but none of the selectors work.
div {
height: 40px;
width: 100px;
background: cyan;
display: inline-block;
}
div:not(.ZoomBar):not(.row.heading) {
background: orange;
}
div:not(.ZoomBar, .row.heading) {
background: orange;
}
div:not(.ZoomBar),
div:not(.row.heading) {
background: orange;
}
<div class="ZoomBar">ZoomBar</div>
<div class="row heading">Heading</div>
<div>Test</div>
You can use something like this
You cannot add unfortunately multiple class in a single not selector.
div {
height: 40px;
width: 100px;
background: cyan;
display: inline-block;
}
div:not(.ZoomBar):not([class="row heading"]){
background: orange;
}
<div class="ZoomBar">ZoomBar</div>
<div class="row heading">Heading</div>
<div class="heading">Heading</div>
<div>Test</div>
The problem with :not() is that it only allows one simple selector at a time. This means any of :not(div), :not(.ZoomBar), :not(.row) and/or :not(.heading). It does not accept either
a compound selector, .row.heading, which consists of two class selectors; or
a comma-separated list of multiple selectors, .ZoomBar, .row.heading.
It's worth noting however that the selectors you've tried will work in jQuery, though not CSS.
Your problem is compounded (heh) by the fact that you're looking for both kinds of exclusions in a single rule. But it's still doable; it simply means you'll need to write a slightly more convoluted rule, with two selectors to account for the two class selectors in .row.heading:
div {
height: 40px;
width: 100px;
background: cyan;
display: inline-block;
}
div:not(.ZoomBar):not(.row),
div:not(.ZoomBar):not(.heading) {
background: orange;
}
<div class="ZoomBar">ZoomBar</div>
<div class="row heading">Heading</div>
<div class="heading row">Heading</div>
<div class="heading foo row">Heading</div>
<div class="heading">Heading</div>
<div>Test</div>
If these are the only possible combinations of class names, you might be able to get away with simply excluding div elements with a class attribute using div:not([class]), but based on your question I suspect that this isn't the case.
For instance, notice in the above snippet that the div[class="heading"] element matches div:not(.ZoomBar):not(.row), and is therefore colored orange. If you may have elements with either class name but not both, those elements will be accounted for.
The answer is this:
div {
height: 40px;
width: 100px;
background: cyan;
display: inline-block;
}
div:not([class*="ZoomBar"]):not([class*="row heading"]):not([class*="heading row"]) {
background: orange;
}
https://jsfiddle.net/ars9fL56/5/

How can i change style of one element mouseovering on another?

I'm trying to change style of WORK div when hovering at one of the hexagons. I've put them all into a table as a container, but it doesn;t seem to work.
Maybe you can give me a hint, thank you.
Example
I just answered another question like this (but was specific to a task). I shall use the same example so you can have a look at how it works.
You can do this just using CSS:
HTML:
<img name="image1" src="./goal/images/normalButton.png" style="vertical-align: middle; width : 183px;" />
<h2 class="mnrImageH2"><span class = "mnrImageSpan">Haberler</span></h2>
CSS:
.mnrImageH2 {
position: absolute;
top:1px;
left: 0;
width: 100%;
}
.mnrImageSpan {
font: bold 24px/45px Helvetica, Sans-Serif;
letter-spacing: -1px;
padding: 10px;
}
h2 {
color: white;
}
img:hover + h2 {
color: #000;
}
So using the + selector we can select the h2 when we hover over an img. Take this and do what you need to do with it.
DEMO HERE
If I correctly understand your point the answer is "You cannot with current schema."
You shall use + or ~ selector. They works if elements have the same parent so you can apply CSS rule if any of hexagon is hovered but you cannot determine particular one.
Add the rule to your example to see what i'm saying:
*:hover + * > * > .work-box{
border: solid red;
}
If your elements have the same parent solution is quite simple - Example
There is good site for Russian speakers about ~ selector
This can help you in your problem and if you are not satisfy by this then comment on this post i will try to solve that also.
<div>
<div class="e" >Company</div>
<div class="e">Target</div>
<div class="e" style="border-right:0px;">Person</div>
</div>
<div class="f">
<div class="e">Company</div>
<div class="e">Target</div>
<div class="e" style="border-right:0px;">Person</div>
</div>
And use hover like this,
.e
{
width:90px;
border-right:1px solid #222;
text-align:center;
float:left;
padding-left:2px;
cursor:pointer;
}
.f .e
{
background-color:#F9EDBE;
}
.e:hover{
background-color:#FF0000;
}

Get value of attribute in CSS

I have this HTML code:
<div data-width="70"></div>
I want to set it's width in CSS equal to the value of data-width attribute, e.g. something like this:
div {
width: [data-width];
}
I saw this was done somewhere, but I can't remember it. Thanks.
You need the attr CSS function:
div {
width: attr(data-width);
}
The problem is that (as of 2021) it's not supported even by some of the major browsers (in my case Chrome):
You cant pass data attribute value directly in to css without pseudo type content.
Rather you can do this way.. CHECK THIS FIDDLE
<div data-width="a"></div><br>
<div data-width="b"></div><br>
<div data-width="c"></div>
CSS
div[data-width="a"] {
background-color: gray;
height: 10px;
width:70px;
}
div[data-width="b"] {
background-color: gray;
height: 10px;
width:80px;
}
div[data-width="c"] {
background-color: gray;
height: 10px;
width:90px;
}
Inline CSS variables are almost as declarative as data attributes, and they are widely supported now, in contrast to the attr(). Check this out:
var elem = document.getElementById("demo");
var jsVar = elem.style.getPropertyValue("--my-var");
function next() {
jsVar = jsVar % 5 + 1; // loop 1..5
elem.style.setProperty("--my-var", jsVar);
}
.d1 {
width: calc( var(--my-var) * 100px );
background-color: orange;
}
.d2 {
column-count: var(--my-var);
}
<button onclick="next()">Increase var</button>
<div id="demo" style="--my-var: 2">
<div class="d1">CustomWidth</div>
<div class="d2">custom columns number custom columns number custom columns number custom columns number custom columns number custom columns number custom columns number</div>
</div>
Another approach would be using CSS Custom Properties with style element to pass values from HTML to CSS.
div {
width: var(--width);
height: var(--height);
background-color: var(--backgroundColor);
}
<div
style="
--width: 50px;
--height: 25px;
--backgroundColor: #ccc;
"
></div>
<div
style="
--width: 100px;
--height: 50px;
--backgroundColor: #aaa;
"
></div>
CSS is static styling information about specific html element and not the other way around. If you want to use CSS to set the width of your div I suggest you do with the use of classes:
HTML:
<div class="foo"></div>
CSS:
.foo {
width: 70px;
}
jsFiddle
I'm just having fun with this, but a jQuery solution would be something like this:
HTML
<div class='foo' data-width='70'></div>
<div class='foo' data-width='110'></div>
<div class='foo' data-width='300'></div>
<div class='foo' data-width='200'></div>
CSS
.foo {
background: red;
height: 20px;
margin-bottom: 10px;
width: 0; /** defaults to zero **/
}
jQuery
$(document).ready(function(){
$('.foo').each(function(i) {
var width = $(this).data('width');
$(this).width(width);
});
});
Codepen sketch here: http://cdpn.io/otdqB
KIND OF AN UPDATE
Not what you're looking for, since you want to pass a variable to the width property. You might as well use a class in this case.
HTML
<div data-width='70'>Blue</div>
CSS
div[data-width='70'] {
width: 70px;
}
Sketch here: http://cdpn.io/jKDcH
<div data-width="70"></div>
use `attr()` to get the value of attribute;
div {
width: attr(data-width);
}
can you try this
$(function(){
$( "div" ).data( "data-width" ).each(function(this) {
$(this).width($(this..data( "data-width" )))
});
});