简体   繁体   中英

How to preserve sibling element position when one sibling is absolutely positioned?

In the snippet below, the child div is normally positioned until it is :hover ed , when it becomes absolutely positioned. The reasoning behind this markup is to simulate a popup style in a limited environment where I can't use a <select> (among other limitations).

When child is hovered, the sibling elements jump around, which is expected, as the contents of the block have changed.

But how can I preserve their positioning? That is, what CSS can I add to prevent the siblings from jumping around when child is hovered.

Javascript is also not allowed, so please no answers using JS.

SKIP TO THE EDIT BELOW

HTML:

<div class="container">
    <div class="child">
        <span class="d4"></span>
        <label><input type="radio" name="radio" value="1"/>One</label>
        <label><input type="radio" name="radio" value="2"/>Two</label>
    </div>
    <input type="text" name="sibling"/>
    <button name="sibling2">Button</button>
</div>

CSS:

.container, .child, button {
    display:inline-block;
}

.child {
    vertical-align: middle;
    width: 35px;
    height: 35px;
}

.child:hover {
    background: gray;
    position:absolute;
    width: 100px;
    height: auto;
}

.child:hover > .d4 {
    display: none;
}

.child label {
    display:none;
}

.child:hover label {
    display: inline-block;
}

.d4 {
    background-position: -411px -1px;
    width: 35px;
    height: 35px;
    background-image: url("https://i.imgur.com/zkgyBOi.png");
    background-repeat: no-repeat;
    color: transparent;
    display: inline-block;
}

Here's a fiddle: http://jsfiddle.net/cpctZ/1/


Edit

New fiddle: http://jsfiddle.net/cpctZ/48/

I simplified my original question too much. In fact there are multiple children in child representing the various dropdown options.

The image and the radios must be sibling elements, in order to conditionally display the correct image based on the selected radio:

.child:not(:hover) input[name="radio"][value="1"]:checked ~ .d4 {
    display: block;
}
.child:not(:hover) input[name="radio"][value="2"]:checked ~ .d8 {
    display: block;
}

Note the sibling selector. If the images are placed in an outer div than the radios, there is no way to say "show the image if its corresponding radio is checked" .

Updated HTML

<div class="container">
    <div class="child">
        <input type="radio" name="radio" value="1" checked="true" />
        <label>d4</label>
        <input type="radio" name="radio" value="2" />
        <label>d8</label>
        <div class="d4"></div>
        <div class="d8"></div>
    </div>
    <input type="text" name="sibling" />
    <button name="sibling2">Button</button>
</div>

So the question remains :\\ How to keep those sibling elements from moving when the child is hovered, while maintaining the feature described above?

Because the image element, is the only visible element when not hovered, in order to preserve natural positioning of sibling when hovered, you need to keep that element out of position absolute.

in other word, wrap everything else in a container and make that one absolute instead.

<div class="child">
    <span class="d4"></span>
    <div class="child-inner">
        <label><input type="radio" name="radio" value="1"/>One</label>
        <label><input type="radio" name="radio" value="2"/>Two</label>
    </div>
</div>

and in order to hide the .d4 , make it opacity=0.01.

.child {
    vertical-align: middle;
    width: 35px;
    height: 35px;
}

.child:hover .child-inner {
    background: gray;
    position:absolute;
    width: 100px;
    height: auto;
    top:0; left:0;
}

.child:hover > .d4 {
    opacity: 0.01;
}

It's also always a good idea to use explicit top and left (or right, or bottom) when using position absolute, as otherwise maybe treated differently in old non-standard browsers. which means you need to get your .container relative. (to be reference point for absolute positioning of .child )

.container {
    position:relative;
}

demo: http://jsfiddle.net/cpctZ/15/

I would suggest floating both the button and text input right (you have to swap the order, see the float: right documentation for why):

<button class="fr" name="sibling2">Button</button>
<input class="fr" type="text" name="sibling"/>

with the CSS:

.container .fr{
float: right;
}

and float the child left with CSS:

.child {
vertical-align: middle;
width: 35px;
height: 35px;
float:left;
}

This works as I think you want it: JSFiddle: http://jsfiddle.net/cpctZ/32/

Edit: To get it working on firefox, give the container a width using

.container{
width 250px;
}

updated fiddle: http://jsfiddle.net/cpctZ/54/

Actually, I think you don't actually need to use positioning at all. This can all be achieved with display:none

JSfiddle Demo

CSS

.container, .child, button {
    display:inline-block;
}

.child {
    vertical-align: middle;
    width: 100px; 
    height: 35px;
}

.child:hover {
    background: gray;

    height: auto;
}

.child:hover > .d4 {
    display: none;
}
.child label {
    display: none;
}

.child:hover label {
    display: inline-block;
}

.d4 {
    background-position: -411px -1px;
    width: 35px;
    height: 35px;
    background-image: url("https://i.imgur.com/zkgyBOi.png");
    background-repeat: no-repeat;
    color: transparent;
    display: inline-block;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM