-3

Is it possible to remove/change styles on sibling class on hover using pure CSS?

I've tried something like this and failed miserably.

HTML:

<ul>
   <li class="item active">name1</li>
   <li class="item">name2</li>
   <li class="item">name3</li>
   <li class="item">name4</li>
</ul>

SCSS

ul {
  padding: 0;
  margin: 0;

  li {
    cursor: pointer;
    list-style: none;
    padding: 12px 16px;

    &.active {
       background-color: $primary-blue;
       color: white;
    }

    &:hover {
       background-color: $primary-blue;
       color: white;

       ~ .active {
         background-color: white !important;
         color: black !important;
       }
    }
  }
}

So what do i want to achieve... I want to HOVER on any element to give it specific style and at the same time i want to hide style of active element. The active element is random, it can be third, second, first, fourth etc... List goes up to 10 elements. This example is simplified.

EDIT! IMPORTANT! I see people have problems understanding what the hell do i want, i hope this plunker will clarify everything :)

https://plnkr.co/edit/RQy04Qv1zy0nukhnlN82

lemek
  • 799
  • 10
  • 21
  • 2
    Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. – Paulie_D Apr 05 '18 at 12:11
  • use simple word : you want to hover on which elemnt and you want to change which element ? – Temani Afif Apr 05 '18 at 12:18
  • I want to hover any element, and hide styles of active element (active element can be any) – lemek Apr 05 '18 at 13:03
  • 1
    Not possible with CSS. You need Javascript. – Paulie_D Apr 05 '18 at 16:07
  • Possible duplicate of [Is there a "previous sibling" CSS selector?](https://stackoverflow.com/questions/1817792/is-there-a-previous-sibling-css-selector) – TylerH Apr 05 '18 at 16:16
  • @MirosławKosiorkiewicz That's what Demo 2 does. If you hover over **anything within the list** the items all behave the same even the active item. If you click the left button, then the normal behavior of an active item persists. **Note all demos in my answer are pure CSS**. So to recap...click the left button so that it says:"INACTIVE", then proceed to hover over the list. The desired behavior is: **all items hovered over behave the same, if nothing is hovered over, active item is highlighted again.** – zer00ne Apr 07 '18 at 20:46

3 Answers3

2

With the given layout, the only pure CSS solution is possible with the order property (using Flexbox or Grid):

ul {
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
}

li {
  cursor: pointer;
  list-style: none;
  padding: 12px 16px;
}
 
li:last-child {
  order: -1; /* moved back up to achieve the same layout */
}
 
.active {
  background-color: blue;
  color: white;
}

li:hover {
  background-color: blue;
  color: white;
}

li:hover ~ .active {
  background-color: white;
  color: black;
}
<ul>
 <li class="item">name2</li>
 <li class="item">name3</li>
 <li class="item">name4</li>
 <li class="item active">name1</li> <!-- has to be the last in order for the ~ selector to take effect -->
</ul>
VXp
  • 11,598
  • 6
  • 31
  • 46
1

"So what do i want to achieve... I want to HOVER on any element to give it specific style and at the same time i want to hide style of active element. The active element is random, it can be third, second, first, fourth etc... List goes up to 10 elements."


It's possible to get that behavior using only CSS, but the layout needs to change because using a pure CSS solution for complex behavior involves:
  1. Specific element positions in relation to other elements. Parent/Ancestor to Child/Descendant and Sibling relationships must be carefully planned due to CSS cascading and inheritance limitations.

  2. Special attributes and default behavior of certain elements that are unique to a group, type, tag, etc. are needed. So just using a list and CSS will not get the behavior you want.

Layout

  1. <input id='chx0' type="checkbox" hidden='true'> are invisible switches that determine other elements' state (a specific set of styles). One state is active for all affected elements when a checkbox is :checked or not checked.

  2. <label id='btn0' for='chx0'></label> are buttons that the user clicks and in turn remotely clicks the checkbox that's targeted by this attribute: for= "chx0"

  3. Due to cascading of rulesets only elements that proceed the checkboxes can be affected which is basically any sibling element that is next down the DOM tree (including that sibling's children/descendants.) I think of it in human family terms:

    Previous-Element-Sibling <section>Older Brother</section>

    Point of Reference 🢂 <input id='chx0' type='checkbox'>

    Next-Element-Sibling <li>Younger Brother</li>

    You can pick on your younger brother but you can't pick on your older brother.

  4. In Demo 2, there are 2 checkbox/label combos:

    • ACTIVE / INACTIVE handles how the .active element behaves.

    • ORDER / CHAOS manipulates the order of the <dd> (not a requirement just added for fun)


I don't know SCSS but from what I can see is that you are expecting a sibling or siblings to change in style, but from what I see, the general sibling combinator ~ is working but the style is ineffectual: white background and black text. This demo is using the adjacent sibling combinator + with the inverse colors so you can actually see a change.

Demo 1

ul {
  padding: 0;
  margin: 0;
}

li {
  cursor: pointer;
  list-style: none;
  padding: 12px 16px;
}

li.active {
  background-color: blue;
  color: white;
}

li:hover {
  background-color: blue;
  color: white;
}

li:hover+li {
  background-color: black !important;
  color: white !important;
}
<ul>
  <li class="item active">name1</li>
  <li class="item">name2</li>
  <li class="item">name3</li>
  <li class="item">name4</li>
</ul>

Demo 2

.dataList {
  display: flex;
  flex-flow: column nowrap;
}

.btn {
  background: rgba(0, 0, 0, 0);
  padding: 3px 5px;
  margin: 20px 0 -15px 30px;
  border: 2px ridge grey;
  border-radius: 4px;
  cursor: pointer;
  display: inline-block;
  width: 12ch;
  text-align: center;
}

#btn0::before {
  content: 'ACTIVE';
  color: green;
}

#chx0:checked~#btn0::before {
  content: 'INACTIVE';
  color: tomato;
}

#btn1::before {
  content: 'ORDER';
  color: blue;
}

#chx1:checked~#btn1::before {
  content: 'CHAOS';
  color: orange;
}

#chx1:checked~.dataList dd:nth-of-type(1) {
  order: 8
}

#chx1:checked~.dataList dd:nth-of-type(2) {
  order: 5
}

#chx1:checked~.dataList dd:nth-of-type(3) {
  order: 6
}

#chx1:checked~.dataList dd:nth-of-type(4) {
  order: 10
}

#chx1:checked~.dataList dd:nth-of-type(5) {
  order: 3
}

#chx1:checked~.dataList dd:nth-of-type(6) {
  order: 2
}

#chx1:checked~.dataList dd:nth-of-type(7) {
  order: 4
}

#chx1:checked~.dataList dd:nth-of-type(8) {
  order: 1
}

#chx1:checked~.dataList dd:nth-of-type(9) {
  order: 7
}

#chx1:checked~.dataList dd:nth-of-type(10) {
  order: 9
}

.data {
  color: white;
  background: rgba(0, 0, 0, 0.8);
  border: 2px inset white;
  padding: 3px 5px
}

.active {
  color: gold;
  border: 2px ridge gold;
  background: rgba(0, 0, 0, 1);
}

.active::after {
  content: ' is ACTIVE';
  font-weight: 900;
}

#chx0:checked~.dataList:hover .data.active {
  border: 2px inset white;
  color: white;
  background: rgba(0, 0, 0, 0.8);
}

#chx0:checked~.dataList:hover .active::after {
  content: '';
  font-weight: normal;
}

.data:hover {
  color: #000;
  background: #fff;
}

.data.active:hover {
  color: lime;
  border-color: lime;
  background: #000;
}

#chx0:checked~.dataList .data.active:hover {
  color: #000;
  background: #fff;
}
<input id='chx0' type='checkbox' hidden='true'>
<input id='chx1' type='checkbox' hidden='true'>

<label id='btn0' class='btn' for='chx0'></label>
<label id='btn1' class='btn' for='chx1'></label>

<dl class='dataList'>
  <dt class='data term'>DATA LIST</dt>
  <dd class='data'>ITEM 0</dd>
  <dd class='data'>ITEM 1</dd>
  <dd class='data'>ITEM 2</dd>
  <dd class='data'>ITEM 3</dd>
  <dd class='data active'>ITEM 4</dd>
  <dd class='data'>ITEM 5</dd>
  <dd class='data'>ITEM 6</dd>
  <dd class='data'>ITEM 7</dd>
  <dd class='data'>ITEM 8</dd>
  <dd class='data'>ITEM 9</dd>
</dl>
zer00ne
  • 41,936
  • 6
  • 41
  • 68
0

I think you might need to add the ampersand to the active selector as well, like so:

li {
    cursor: pointer;
    list-style: none;
    padding: 12px 16px;

    &.active {
       background-color: $primary-blue;
       color: white;
    }

    &:hover {
       background-color: $primary-blue;
       color: white;

       ~ &.active {
         background-color: white !important;
         color: black !important;
       }
    }
  }
CoenFuze
  • 484
  • 2
  • 7
  • Sorry but no. I've tried a lot of variations :/ I wonder if its possible at all. – lemek Apr 05 '18 at 12:17
  • A no, it's not... see https://stackoverflow.com/questions/12574668/change-color-of-sibling-elements-on-hover-using-css – CoenFuze Apr 05 '18 at 12:29