I have 3 boxes which look like the one in the example. I want to apply a certain style on the non-hovered boxes when a user hovers over a certain box (The boxes are always siblings).
Here is how it should work -
Hover over Box 1 - Box 2 and Box 3 should be greyed
Hover over Box 2 - Box 1 and 3 should be greyed
Hover over Box 3 - Box 1 and 2 should be greyed
.test {
width: 100px;
background-color: #009AFD;
height: 100px;
display: inline-block;
margin-right: 5px;
text-align: center;
}
.test:hover ~ .test {
width: 100px;
background-color: #ddd;
height: 100px;
display: inline-block;
margin-right: 5px;
text-align: center;
}
<div class="test">
Box 1
</div>
<div class="test">
Box 2
</div>
<div class="test">
Box 3
</div>
I can get it working for Box 1. Can somebody help me how I can do it elegantly for Box 2 and 3.
Note: No jQuery or Javascript should be used (which would be a cakewalk in this case).
You can not select “upwards” with current CSS selectors, so 2 and 3 are not possible – not directly. You could put all elements into a common container element, and when that is hovered make all boxes gray, and then the actual box hovered blue again:
.test {
width: 100px;
background-color: #009AFD;
height: 100px;
display: inline-block;
margin-right: 5px;
text-align: center;
}
.container:hover .test {
background:#ddd;
}
.container .test:hover {
background-color: #009AFD;
}
<div class="container">
<div class="test">Box 1</div>
<div class="test">Box 2</div>
<div class="test">Box 3</div>
</div>
(No need btw. to repeat all those properties that stay the same in the hovered state.)
This however will also apply the hover effect when you are not directly hovering one of the boxes, but also when the container element is hovered in the margin between the boxes – so when in between the boxes, all three of them will become gray.
To fight that effect, you need to get a little creative: By not having the boxes laid out in normal flow, but positioning them absolutely instead, you can make the container element take up no space at all, so it won’t be hovered in the “margins” between the boxes. Hovering the boxes themselves however still triggers :hover for the container element, since the boxes are its children and therefor hovering them means hovering the parent element as well, even if the parent element is not “present” in that space where the mouse cursor is hovering over.
.container {
position: relative;
}
.test {
position: absolute;
top: 0;
left: 0;
width: 100px;
background-color: #009AFD;
height: 100px;
display: inline-block;
text-align: center;
}
#box2 {
left: 110px;
}
#box3 {
left: 220px;
}
.container:hover .test {
background: #ddd;
}
.container .test:hover {
background-color: #009AFD;
}
<div class="container">
<div class="test" id="box1">Box 1</div>
<div class="test" id="box2">Box 2</div>
<div class="test" id="box3">Box 3</div>
</div>
Of course then you might have to use some additional trickery to keep following elements in normal flow at the same positions they would take, had the absolute positioning not taken the boxes out of flow (like giving the next element a margin-top or something).
And of course the whole thing only works this “simple”, because you want the color for the siblings of the hovered boxes to be the same. Would you wish for different colors for them, then additional trickery of sorts might be needed.
This will do it:
.test {
width: 100px;
background-color: #009AFD;
height: 100px;
display: inline-block;
margin-right: 5px;
text-align: center;
}
.parent:hover > div {
width: 100px;
background-color: #ddd;
height: 100px;
display: inline-block;
margin-right: 5px;
text-align: center;
}
.parent:hover > div:hover {
background-color: #009AFD;
}
<div class="parent">
<div class="test">Box 1</div>
<div class="test">Box 2</div>
<div class="test">Box 3</div>
</div>
Enclose the divs in a parent div. Use this selector to change all the children: .parent:hover > div. And this selector to exempt the child that is being hovered: .parent:hover > div:hover.
.test:hover ~ .test selects .test elements which are following siblings of a hovered .test element.
Instead, you can try :not(). The selector below will match all .test elements which are not hovered:
.test:not(:hover)
.test {
width: 100px;
background-color: #009AFD;
height: 100px;
display: inline-block;
margin-right: 5px;
text-align: center;
}
.test:not(:hover) {
background-color: #ddd;
}
<div class="test">
Box 1
</div>
<div class="test">
Box 2
</div>
<div class="test">
Box 3
</div>
If you only want to match the non-hovered elements when one is hovered, you can use
:hover > .test:not(:hover)
.test {
width: 100px;
background-color: #009AFD;
height: 100px;
display: inline-block;
margin-right: 5px;
text-align: center;
}
:hover > .test:not(:hover) {
background-color: #ddd;
}
<div class="test">
Box 1
</div>
<div class="test">
Box 2
</div>
<div class="test">
Box 3
</div>
Alternatively, if you want it to work on old browsers that don't support :not(), you can apply the style to all elements, and reset in in the hovered element.
.test {
/* Set styles for non-hovered */
}
.test:hover {
/* Set styles for hovered */
}
.test {
width: 100px;
background-color: #ddd;
height: 100px;
display: inline-block;
margin-right: 5px;
text-align: center;
}
.test:hover {
background-color: #009AFD;
}
<div class="test">
Box 1
</div>
<div class="test">
Box 2
</div>
<div class="test">
Box 3
</div>
.test {
/* Set styles for non-hovered */
}
:hover > .test:hover {
/* Set styles for non-hovered when another is hovered */
}
.test:hover {
/* Set styles for hovered */
}
.test {
width: 100px;
background-color: #009AFD;
height: 100px;
display: inline-block;
margin-right: 5px;
text-align: center;
}
:hover > .test {
background-color: #ddd;
}
.test:hover {
background-color: #009AFD;
}
<div class="test">
Box 1
</div>
<div class="test">
Box 2
</div>
<div class="test">
Box 3
</div>
Related
I already have a css hover where when hovering over someones name, a card to the side appears with more information about that user.
Is it possible to have another hover on top of the first hover? So another card appears with even more information.
Name (hover on name) > d.o.b, address , etc (hover on their d.o.b for example) > second card appears with further info.
Thanks,
Jack
At the moment I just have the initial as a radio button which brings up the first info card, then I have a hover based off of that to show the second info card.
Here's an simple example I made:
#a {
width: 100px;
background: blue;
height: 100px;
}
#a:hover {
background: yellow;
}
#b {
width: 50px;
background: black;
height: 50px;
}
#b:hover {
background: red;
}
<div id="a">
<div id="b">
</div>
</div>
.parent {
width: 100px;
height: 100px;
background-color: lightpink;
}
.child,
.sub-child {
display: none;
width: 100px;
height: 100px;
position: relative;
right: -100px;
}
.child {
background-color: lightgreen;
}
.sub-child {
background-color: lightblue;
}
/* Show the child when hovering on the parent */
.parent:hover .child {
display: block;
}
/* Show the sub-child when hovering on the child */
.child:hover .sub-child {
display: block;
}
/* Not needed, just styling */
div:hover {
outline: 2px solid red;
}
<div class="parent">
<div class="child">
<div class="sub-child"></div>
</div>
</div>
I have two div elements as below:
<div class="div1">
This is div 1
</div>
<div class="div2">
This is div 2
</div>
With css as:
.div1 {
border-style: solid;
float: left;
width: 50%;
}
.div2 {
border-style: solid;
margin-left: 50%;
padding-left: 10px;
}
I want to add a third div which has nothing but a symbol through css.
<div class="div3">
</div>
with css:
.div3:after {
font-family: "FontAwesome";
content: "\f100";
color: blue;
font-size: 1.5em;
}
For this to nicely position between the two original div's, I changed div 2's css to:
.div2 {
border-style: solid;
margin-left: 51%;
padding-left: 6px;
}
This looks ok on FullScreen. However, when I minimize the browser window to a smaller size, div2 starts overlapping div3.
How can I nicely position div3 between div1 and div2 with even space at both sides of div2?
Here's the JSFiddle for my try: https://jsfiddle.net/d8nuw2m3/5/
Edit:
The flex solution provided below by Roy works fine. However, assume that the content of left and right div's grows a lot. In which case, scroll bar will appear. What if in this case, I want to keep the position of the middle div fixed as I scroll down ?
Adding position: fixed to div3 css doesn't work.
Here's the fiddle: https://jsfiddle.net/zL8sc2a9/
Solution #1
You could use flex for this.
Wrap all div's in a container with display: flex:
<div class="flex-container">
<div class="div1">
This is div 1
</div>
<div class="div3">
</div>
<div class="div2">
This is div 2
</div>
</div>
.flex-container {
display: flex;
}
Let the div1 and div2 grow equally (remove widths, margins, paddings):
.div1 {
border-style: solid;
flex-grow: 1;
}
.div2 {
border-style: solid;
flex-grow: 1;
}
Set a fixed width to the div3:
.div3 {
width: 18px;
}
That's it! Flex will do the trick for you: https://jsfiddle.net/1amuwfj5/
Solution #2
Use calc() to subtract div3 width from div1 and div2. General idea:
.div1 {
border-style: solid;
float: left;
width: calc(50% - 15px); /* we subtract 9x (half of div3) and 6px (border width) */
}
.div2 {
border-style: solid;
float: right;
width: calc(50% - 15px);
}
.div3 {
width: 18px;
}
Example: https://jsfiddle.net/1amuwfj5/1/
You can achieve this adding a div around it and using display: flex;. Floating elements is really the old way to do this.
Edit
I updated the snippet to have the .div3:after fixed with scrolling.
.page {
background-color: #eee;
height: 150vh;
}
.wrapper {
display: flex;
justify-content: space-between;
}
.div1 {
border-style: solid;
width: 50%;
margin-right: .5em;
}
.div2 {
border-style: solid;
width: 50%;
margin-left: 1.5em;
}
.div3:after {
position: fixed;
font-family: "FontAwesome";
content: "\f100";
color: blue;
font-size: 1.5em;
}
<div class="page">
<div class="wrapper">
<div class="div1">
This is div 1
</div>
<div class="div3">
</div>
<div class="div2">
This is div 2
</div>
</div>
</div>
On to the real question. I started learning HTML and I ran into a circumstance that I don't understand why it happens and was hoping someone could explain this to me.
Above is my code and what I don't get is why the introduction of the word text in box1 causes the whole box to be displayed on a new line.
Once the text is removed it realigns. any help is welcome.
I'm going to end this off by saying that I tried pasting in code (using the code blocks button and surrounding my code with <code> and <pre> tags but the editor would not display the code or would break the code block by every second)
Try vertical-align:top; with inline-block.
When we use inline-block we can align blocks in 3 different way's, like if 2 block have large height and one has small then using vertical-align:top; make all three block aligned at top using vertical-align:middle; make these three block aligned middle and using vertical-align: bottom; make these blocks aligned at the bottom side
div {
display: inline-block;
vertical-align:top;
margin: 25px;
}
p {
padding: 10px;
text-align: center;
}
#box1 {
width: 100px;
height: 100px;
background-color: red;
}
#box2 {
width: 100px;
height: 100px;
background-color: blue;
}
#box3 {
width: 100px;
height: 100px;
background-color: yellow;
}
<div id="container">
<div id="box1"><p>text</p></div>
<div id="box2"></div>
<div id="box3"></div>
</div>
It is because you have a pixel value for the width and height of all 3 of your divs. The text "increases" the width and pixel value of your divs.
UPDATE
Why not use the float property?
div {
float: left;
display: block;
margin: 25px;
}
p {
padding: 10px;
text-align: center;
}
#box1 {
width: 100px;
height: 100px;
background-color: red;
}
#box2 {
width: 100px;
height: 100px;
background-color: blue;
}
#box3 {
width: 100px;
height: 100px;
background-color: yellow;
}
<div id="container">
<div id="box1"><p>text</p></div>
<div id="box2"></div>
<div id="box3"></div>
</div>
I build HTML/CSS/JS menu and want to align arrow to the right to point that this element is submenu.
My problem that in Firefox triangle ("▶" sign) shown on next line instead of current line...
Chromium shown both cases fine.
There are bugs in BTS that similar to my situation:
https://bugzilla.mozilla.org/show_bug.cgi?id=488725
I try 2 strategy, this my HTML structure:
<div class="name1">Submenu 1<span class="sub">▶</span></div>
Item 1
Item 2
<div class="name2">Submenu 2</div>
Item 1
Item 2
and this my CSS which shown issue:
a, .name1, .name2 {
display: block;
white-space: nowrap;
}
.name1 > .sub {
float: right;
}
.name2:after {
content: "▶";
float: right;
}
JS Fiddle for playground.
I remember I read code where margin-right: -16px or similar used with background image or something else to make such design but I can't remember exactly how.
What workaround possible?
UPDATE I make more complete example, HTML:
<div class="container">
Top level menu
<div class="box">
<div class="name1">Very long submenu 1<span class="sub">▶</span></div>
Item 1 1 1
Item 2
<div class="name2">Very long submenu 2</div>
Item 1
Item 2
</div>
</div>
CSS:
a { border: green 1px dotted; margin: 2px; }
a, .name1, .name2 {
display: block;
white-space: nowrap;
}
.name1 > .sub {
display: inline-block;
float: right;
}
.name2:after {
content: "▶";
float: right;
}
.container {
display: inline-block;
background: gold;
position: relative;
}
.box { display: none; }
.container:hover > .box {
display: block;
position: absolute;
top: 100%;
}
getting rid of "white-space: nowrap" helps
Finally I solve problem:
<div class="container">
Top level menu (hover on me)
<div class="box">
<div class="submenu">
<div class="name">Long submenu 1</div>
<div class="box">
Item 1
Item 2
</div>
</div>
Item 1 1 1
Item 2
<div class="submenu">
<div class="name">Very long submenu 2</div>
<div class="box">
Item 1
Item 2
Item 3
</div>
</div>
Item 1
Item 2
</div>
</div>
and:
.container {
display: inline-block;
background: gold;
position: relative;
}
.box { display: none; }
.container:hover > .box {
display: block;
position: absolute;
top: 100%;
}
.container .submenu {
position: relative;
}
.container .submenu:hover > .box {
display: block;
position: absolute;
top: 0;
left: 100%;
}
a, .name {
white-space: nowrap;
display: block;
}
.name {
padding-right: 1.2em;
position: relative;
}
.name:after {
content: "▶";
position: absolute;
top: 0;
left: 100%;
margin-left: -1em;
}
Essential part is to make element with triangle as block and position: relative and reserve space for triangle by padding-right: -1.2em and position triangle by position: absolute after element and move back triangle by margin-left: -1em.
I am trying to get an element to appear on top of its parent's sibling but it only appears underneath. I have tried changing the z-index and playing around with floats but can't find a working solution. I want to keep the Stuff span inside its parent span as it is related to it and works well if CSS is disabled.
He is what I have so far http://jsfiddle.net/P3qwx/
HTML
<div class="grid">
<span>
<h4>1</h4>
</span>
<span>
<h4>2</h4>
<span>Stuff</span>
</span>
<span>
<h4>3</h4>
</span>
<span>
<h4>4</h4>
</span>
</div>
CSS
.grid > span {
background-color: #ffff00;
display: inline-block;
width: 100px;
height: 100px;
vertical-align: top;
z-index: 5;
}
.grid > span > span {
background-color: #ff00ff;
display: inline-block;
width: 250px;
z-index: 10;
}
This is what I get (FF30)
This is what I want
You can try this:
Demo
.grid > span > span {
background-color: #ff00ff;
display: inline-block;
width: 250px;
z-index: 10;
position:absolute;
}
Pradeep Pansari's answer is all good but I would like to explain a little bit more thus provide another solution to your question.
First of all, your z-index code doesn't work at all. z-index only has an effect if an element is positioned.
Now, let's add the position. Your css is now
.grid > span {
background-color: #ffff00;
display: inline-block;
width: 100px;
height: 100px;
vertical-align: top;
z-index: 5;
position:relative;
}
.grid > span > span {
background-color: #ff00ff;
display: inline-block;
width: 250px;
z-index: 10;
position:absolute;
}
This is the result http://jsfiddle.net/P3qwx/4/
What's happening here? Why is the purple block is still hidden under the third and fourth yellow blocks?
This is because for each yellow block, there is a stacking context created
So long story short, your purple block and its z-index only takes effect under the second yellow block, it has no power whatsoever under the third and fourth one because of different stacking context. Here's the hierarchy
Yellow block 1 (z-index 5)
Yellow block 2 (z-index 5)
Purple block (z-index 10)
Yellow block 3 (z-index 5)
Yellow block 4 (z-index 5)
Once we got to this point, fixing is simple, either removing the z-index and setting the position to absolute and let the default stacking rule takes care of business
Demo
.grid > span {
background-color: #ffff00;
display: inline-block;
width: 100px;
height: 100px;
vertical-align: top;
}
.grid > span > span {
background-color: #ff00ff;
display: inline-block;
width: 250px;
position:absolute;
}
Or (I suppose you don't want this but just for for completeness sake..)
Demo
HTML
<div class="grid">
<span class="span1">
<h4>1</h4>
</span>
<span class="span2">
<h4>2</h4>
<span class="span5">Stuff</span>
</span>
<span class="span3">
<h4>3</h4>
</span>
<span class="span4">
<h4>4</h4>
</span>
</div>
CSS
.span1 {
background-color: #ffff00;
display: inline-block;
width: 100px;
height: 100px;
vertical-align: top;
position:relative;
z-index: 1;
}
.span2 {
background-color: #ffff00;
display: inline-block;
width: 100px;
height: 100px;
vertical-align: top;
position:relative;
z-index: 5;
}
.span3 {
background-color: #ffff00;
display: inline-block;
width: 100px;
height: 100px;
vertical-align: top;
position:relative;
z-index: 3;
}
.span4 {
background-color: #ffff00;
display: inline-block;
width: 100px;
height: 100px;
vertical-align: top;
position:relative;
z-index: 4;
}
.span5 {
background-color: #ff00ff;
display: inline-block;
width: 250px;
position:absolute;
z-index:1;
}