After seeing the different selectors available (as of CSS3), the difference between the + and ~ seem to be nearly the same. And it also appears there is no selector with opposite functionality to ~.
Taken from www.w3schools.com:
div + p: Selects all <p> elements that are placed immediately after <div> elements.
p ~ ul: Selects every <ul> element that are preceded by a <p> element.
The effect of p ~ ul can be rewritten as:
Selects all <ul> elements that are placed after a <p> element.
Because preceded by a <p> means the <p> is before the <ul>.
This leaves the only difference between these operators being that + only select elements immediately after (I assume all consecutive occurrences), whereas ~ selects elements anywhere after (but still with the same parent).
Is my understanding of the difference correct?
Originally I thought the two operators were opposites due to the somewhat confusing english.
So, my follow-up questions is this:
How can I select every element placed before (or immediately before) another element?
I'm working with this case scenario:
I have 2 div's side-by-side in the same parent div.
<div id="container">
<div id="column_left">
</div>
<div id="column_right">
</div>
</div>
When I hover either div, both should gradually become more opaque using CSS transitions. When I'm not hovering either, they should become more transparent.
So, to select the right column when the left is hovered I would using the selector:
#column_left:hover+column_right {
opacity: 0.9;
transition: opacity 300ms;
-webkit-transition: opacity 300ms;
}
Now, how can I select the left column when the right is hovered?
Here is my CSS so-far:
div {
border: 1px solid black;
background: #262626;
}
#left {
float: left;
width: 200px;
height: 200px;
margin: 0;
transition: background 300ms;
-webkit-transition: background 300ms;
}
#right {
display: inline-block;
width: 200px;
height: 200px;
transition: background 300ms;
-webkit-transition: background 300ms;
}
#left:hover,#left:hover~#right {
background: #909090;
transition: background 300ms;
-webkit-transition: background 300ms;
}
<div id=left>
</div>
<div id=right>
</div>
Is my understanding of the difference correct?
Yes. Selectors L3 defines those two types of sibling combinators (emphasis mine):
Adjacent sibling combinator
The adjacent sibling combinator is made of the "plus sign" (U+002B, +)
character that separates two sequences of simple selectors. The
elements represented by the two sequences share the same parent in the
document tree and the element represented by the first sequence
immediately precedes the element represented by the second one.
General sibling combinator
The general sibling combinator is made of the "tilde" (U+007E, ~)
character that separates two sequences of simple selectors. The
elements represented by the two sequences share the same parent in the
document tree and the element represented by the first sequence
precedes (not necessarily immediately) the element represented by the second one.
How can I select every element placed before (or immediately before) another element?
As explained in Is there a previous sibling selector?, it's not possible to do that with Selectors L3. Selectors L4 may introduce some way to do it, but probably it will only be available in JS (e.g. through querySelector) but not in CSS stylesheets because of performance reasons.
A solution for your specific use case
When I hover either div, both should gradually become more opaque using CSS transitions. When I'm not hovering either, they should become more transparent.
.wrap {
float:left;
overflow:hidden
}
div {
border: 1px solid black;
}
#left {
float: left;
width: 200px;
height: 200px;
margin: 0;
background-color: red;
transition: background 300ms;
-webkit-transition: background 300ms;
}
#right {
float:left;
width: 200px;
height: 200px;
background-color: blue;
transition: background 300ms;
-webkit-transition: background 300ms;
}
.wrap:hover > #right,
.wrap:hover > #left {
background: #909090;
transition: background 300ms;
-webkit-transition: background 300ms;
}
<div class="wrap">
<div id=left>
</div>
<div id=right>
</div>
</div>
Related
Hi I am new to css and I have came across this text underline animation, I couldn't understand how it works. If I just take something out of this code it just stops working. Thanks in advance!
body {
background-color: black;
}
body a {
font-weight: 200;
font-size: 18px;
text-transform: uppercase;
text-decoration: none;
position: relative;
color: #fff;
}
body a:visited {
color: white;
}
body a:hover {
color: white;
}
body a:after {
content: "";
position: absolute;
bottom: 0;
left: 0;
width: 0%;
border-bottom: 2px solid #fff;
transition: 0.4s;
}
body a:hover:after {
width: 100%;
}
<body>
aaaaaaaaaaaaaaaaaaaaaaaaaaaaa
</body>
An :after psuedo CSS means that another "virtual" element is appended after the selected element
the psuedo element appended on a:after is a simple element with bottom border but is without width (0%)
the transition property on that element means, that all properties of that element when changed will be animated
so...
when you hover the element (stated in body a:hover:after) - the width of that "virtual" element is set to 100% - and the animation takes place
What's really important here are the pseudo-elements ":after" and ":before" (although this last one not present here).
This part here is what makes it come to life:
body a:after {
content: "";
position: absolute;
bottom: 0;
left: 0;
width: 0%;
border-bottom: 2px solid #fff;
transition: 0.4s;
}
You see, basically you're looking at the declaration of properties of an element's pseudo element. (You might want to dig in a bit into CSS-CSS3).
It states that after triggering the hover event on an anchor that is a child of body it will make its pseudo element have a bottom border of 2 pixels of width, with a white solid color and a transition of 0.4 seconds.
We can tell by the other declarations that the width of the pseudo-element is 0% in its initial state and after hovering it goes to 100% with a transition (making it go from left to right as seen in the example).
There's much things to consider in this CSS code but you should really learn the basics!
This line creates the animation:
transition: 0.4s;
You will notice that the body a:hover:after rule has a width of 100%. Well, that transition property tells the render engine that there is an animation to be performed on any property that has a value change between the normal and hover state.
When you hover, the render engine reads that you want to set the width property to 100%. Before hover it was set at 0%. Transition says, "ok, on hover, animate the width property from 0 to 100% over a period of 4 tenths of a second.
This will be true of any properties that differ between the hover and non-hover state. In other words, you could animate more than one property at a time so long as the two states define the same property with different values.
This question already has answers here:
How do I reduce the opacity of an element's background using CSS?
(29 answers)
Closed 7 years ago.
I have following CSS
.dropdown-menu {
background-color: black;
opacity: 0.6;
color: white;
}
.dropdown-menu > li {
background-color: black;
opacity: 1;
color: white;
}
When HTML element (which uses this above CSS) is loaded I'm getting opacity sets as expected from .dropdown-menu, the problem is that this opacity is inherited inside dropdown-menu > li element event when I'm using an !important declaration on opacity.
So how to overcome this (Opacity should remain 0.6 on parent element) and on this child I want opacity 1?
Instead of using opacity for the parent element, declare your colors in rgba format.
.dropdown-menu {
background-color: rgba(0,0,0,.6);
color: rgba(255,255,255,.6);
}
This way, you will retain the opacity of the parent element, as well as your child elements will have an opacity of 1.
Browser support for the same is pretty decent as well.
Also, I read this in your question, "The problem is that this opacity is inherited"
No, it isn't inherited.
It's important to know that opacity sets the opacity value for an element and all of its children; where RGBA sets the opacity value only for a single declaration.
So you should use something like:
.dropdown-menu {
background-color: rgba(0,0,0,.6);
color: rgba(255,255,255,.6);
}
(Of course, you can also use the HSLA-property for this.)
Remember that the opacity-property isn't fully supported by all browsers, please check this SA-topic for more info on this: CSS background opacity with rgba not working in IE 8
I have a script (JsFiddle here) that detects when an li block element is vertically centered on a page and assigns it a .centered class to make it bigger via CSS.
.centered {
height: 30vh;
background-color: #bbb;
-webkit-transition: height 0.6s;
}
Once the central element is identified I manage to select the next sibling to via this:
.centered + li {
height: 20vh;
background-color: #ccc;
-webkit-transition: height 0.6s;
}
The problem arises when I try to select the sibling element preceding the .centered element in pure CSS
After looking at this question from 2011 I tried playing with the :has() pseudo class suggested in one of the comments and other selectors, but with no luck.
This CSS4 relational pseudo class could have done the trick, but is not currently supported:
li:has(+ .centered) {
height: 20vh;
background-color: #Fcc;
-webkit-transition: height 0.6s;
}
I also tried to select the last-of-type of li elements that are not siblings of .centered, but either :not() supports only simple selectors or I'm just not getting how to chain the selectors properly.
Here's the non-working selector:
li:not(.centered ~ li):last-of-type {
height: 20vh;
background-color: #Fcc;
-webkit-transition: height 0.6s;
}
QUESTION: Is there any combination of pseudo classes and selectors that could do the trick in pure CSS?
My hope is that some progress has been made since those questions have been asked.
Is there any combination of pseudo classes and selectors that could do the trick in pure CSS?
There isn't; the reason :not(.centered ~ li) doesn't work is indeed that it only currently supports simple selectors — like :has(), :not() will only accept combinators in Selectors 4. Since there are no pseudo-classes that currently accept combinators, and the only available sibling combinators go forward, you are left with a very restricted domain language in this regard. This is why those additions to Selectors were made.
As for progress... progress on the :has() pseudo-class has been eh. Last I heard, the working group was still deciding between allowing a subset of :has() in CSS or separating that out into its own pseudo-class, and vendors were going to see how much of it they could implement in CSS for this to work. But I don't think there has been any data yet.
Following the confirmation that it is impossible by #BoltClock and the #torazaburo comment I changed my initial jQuery selection starting element
From this:
middleElement = this;
$(this).toggleClass("centered", true);
To this:
middleElement = this;
$(this).prev().toggleClass("top", true);
Without adding extra javascript code, I could then change my CSS selectors.
From:
.centered { /*selects the middle element */
height: 30vh;
background-color: #bbb;
-webkit-transition: height 0.6s;
}
.centered + li { /*selects the next sibling after middle element */
height: 20vh;
background-color: #ccc;
-webkit-transition: height 0.6s;
}
li:has(+ .centered){ /*not supported at time of writing*/
height: 20vh;
background-color: #Fcc;
-webkit-transition: height 0.6s;
}
To:
.top, .top + li + li { /* selects the siblings before and after the middle one*/
height: 20vh;
background-color: #ccc;
-webkit-transition: height 0.6s;
}
.top + li { /* This selects the middle element*/
height: 30vh;
background-color: #bbb;
-webkit-transition: height 0.6s;
}
>> JSFiddle
I have an ID which shows an image at the top of my site
<div id="Introduction">
When I click the <div> it toggles the class active which works.
However the background image does not seem to change - can anybody tell me why?
I know the class is being added because I can see by inspecting the element.
#Introduction
{
width: 95%;
height: 280px;
padding-top: 85px;
padding-left: 5%;
background-image: url('background1.jpg');
background-size: cover;
background-position: center center;
transition: all 1s ease-in-out;
}
#Introduction .active
{
background-image: url('background2.jpg');
}
You have an error in your selector, you're checking for .active that is a descendant of #Introduction. It should be #Introduction.active, without a space.
Just remove the white space between #Introduction .active. Like #Introduction.active.
An space between two simple selectors A B is called descendant combinator, which would select all Bs that are descendants of As.
In this particular instance, .active class is added to the div having #Introduction ID as well, hence you should use those two selectors without any combinators (spaces, > greater-than sign, etc.).
So is it possible to make this work
#element img:hover #otherelement {...}
like
#element:hover #otherelement {...}
it's important for img to stay specified, because images are automatic in what I'm making.
As img cannot hold any other nested tag, I assume you are targeting the adjacent element, you can use adjacent selector here using +
#element img:hover + #otherelement {...}
The above selector will select the element next to img tag when the image is hovered.
Note: Above selector will work only if you've your markup like
<div id="element">
<img src="#" />
<div id="otherelement"></div >
</div >
But will fail if you've markup like
<div id="element">
<img src="#" />
</div >
<div id="otherelement"></div >
What you can do is selecting next element(s) by:
Adjacent sibling combinator
element1 + element2 Selects every element2 element that are placed immediately after element1 element(s). They're siblings.
#element img:hover + #otherelement
If the #otherelement is placed right after img, it'll be selected when img is hovered.
Another option is:
General sibling combinator
element1 ~ element2 Matches occurrences of element2 that are preceded by element1 while they have the same parent. They're siblings too, but element2 doesn't have to be immediately preceded by element1.
#element img:hover ~ #otherelement
If #otherelement and img are siblings, and #otherelement is placed somewhere after the img, it'll be selected when img is hovered.
Here is an example
HTML
<div id="parent">
<img src="http://lorempixel.com/200/200/" alt="Sport">
<div class="text">This is a text.</div>
</div>
CSS:
#parent {
overflow: hidden;
width: 200px;
height: 200px;
}
.text {
position: relative;
-webkit-transition: .3s all;
-moz-transition: .3s all;
transition: .3s all;
background-color: rgba(255,255,255,.5);
height: 40px;
line-height: 40px;
}
#parent img:hover + .text {
top: -40px;
}
What your first selector is looking for is something called #otherelement inside an image. Images can't have child elements.
If the element is a sibling of the image, you might want to try img:hover~#otherelement or img:hover+#otherelement.
Yes it is, try:
#element:hover + #otherelement {...}
or
#element:hover ~ #otherelement {...}
You can use the :hover pseudo class on any element. There are considerations to be made in regards to cross-browser. You can use a polyfill like Selectivizr for that, though.
As for your question, you might want to consider targeting a shared ancestor for both elements you are trying to target with the hover and apply your styles that way.